Merge
This commit is contained in:
commit
f03bea190f
@ -53,9 +53,6 @@ public abstract class NashornException extends RuntimeException {
|
||||
// underlying ECMA error object - lazily initialized
|
||||
private Object ecmaError;
|
||||
|
||||
/** script source name used for "engine.js" */
|
||||
public static final String ENGINE_SCRIPT_SOURCE_NAME = "nashorn:engine/resources/engine.js";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
import static jdk.nashorn.internal.runtime.Source.sourceFor;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -34,13 +32,10 @@ import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
@ -58,7 +53,6 @@ import javax.script.SimpleBindings;
|
||||
import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ErrorManager;
|
||||
import jdk.nashorn.internal.runtime.Property;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
@ -98,9 +92,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
// This is the initial default Nashorn global object.
|
||||
// This is used as "shared" global if above option is true.
|
||||
private final Global global;
|
||||
// initialized bit late to be made 'final'.
|
||||
// Property object for "context" property of global object.
|
||||
private volatile Property contextProperty;
|
||||
|
||||
// default options passed to Nashorn Options object
|
||||
private static final String[] DEFAULT_OPTIONS = new String[] { "-doe" };
|
||||
@ -122,30 +113,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
}
|
||||
|
||||
// load engine.js
|
||||
private static Source loadEngineJSSource() {
|
||||
final String script = "resources/engine.js";
|
||||
try {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<Source>() {
|
||||
@Override
|
||||
public Source run() throws IOException {
|
||||
final URL url = NashornScriptEngine.class.getResource(script);
|
||||
return sourceFor(NashornException.ENGINE_SCRIPT_SOURCE_NAME, url);
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (final PrivilegedActionException e) {
|
||||
if (Context.DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Source object for engine.js
|
||||
private static final Source ENGINE_SCRIPT_SRC = loadEngineJSSource();
|
||||
|
||||
NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) {
|
||||
this(factory, DEFAULT_OPTIONS, appLoader);
|
||||
}
|
||||
@ -248,33 +215,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
return getInterfaceInner(thiz, clazz);
|
||||
}
|
||||
|
||||
// These are called from the "engine.js" script
|
||||
|
||||
/**
|
||||
* This hook is used to search js global variables exposed from Java code.
|
||||
*
|
||||
* @param self 'this' passed from the script
|
||||
* @param ctxt current ScriptContext in which name is searched
|
||||
* @param name name of the variable searched
|
||||
* @return the value of the named variable
|
||||
*/
|
||||
public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
|
||||
if (ctxt != null) {
|
||||
final int scope = ctxt.getAttributesScope(name);
|
||||
final Global ctxtGlobal = getNashornGlobalFrom(ctxt);
|
||||
if (scope != -1) {
|
||||
return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal);
|
||||
}
|
||||
|
||||
if (self == UNDEFINED) {
|
||||
// scope access and so throw ReferenceError
|
||||
throw referenceError(ctxtGlobal, "not.defined", name);
|
||||
}
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
// Implementation only below this point
|
||||
|
||||
private static Source makeSource(final Reader reader, final ScriptContext ctxt) throws ScriptException {
|
||||
@ -426,47 +366,12 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
}, CREATE_GLOBAL_ACC_CTXT);
|
||||
|
||||
nashornContext.initGlobal(newGlobal);
|
||||
nashornContext.initGlobal(newGlobal, this);
|
||||
newGlobal.setScriptContext(ctxt);
|
||||
|
||||
final int NON_ENUMERABLE_CONSTANT = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE;
|
||||
// current ScriptContext exposed as "context"
|
||||
// "context" is non-writable from script - but script engine still
|
||||
// needs to set it and so save the context Property object
|
||||
contextProperty = newGlobal.addOwnProperty("context", NON_ENUMERABLE_CONSTANT, ctxt);
|
||||
// current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as
|
||||
// NetBeans identifies this assignment as such a leak - this is a false positive as we're setting this property
|
||||
// in the Global of a Context we just created - both the Context and the Global were just created and can not be
|
||||
// seen from another thread outside of this constructor.
|
||||
newGlobal.addOwnProperty("engine", NON_ENUMERABLE_CONSTANT, this);
|
||||
// global script arguments with undefined value
|
||||
newGlobal.addOwnProperty("arguments", Property.NOT_ENUMERABLE, UNDEFINED);
|
||||
// file name default is null
|
||||
newGlobal.addOwnProperty(ScriptEngine.FILENAME, Property.NOT_ENUMERABLE, null);
|
||||
// evaluate engine.js initialization script this new global object
|
||||
try {
|
||||
evalImpl(compileImpl(ENGINE_SCRIPT_SRC, newGlobal), ctxt, newGlobal);
|
||||
} catch (final ScriptException exp) {
|
||||
throw new RuntimeException(exp);
|
||||
}
|
||||
return newGlobal;
|
||||
}
|
||||
|
||||
// scripts should see "context" and "engine" as variables in the given global object
|
||||
private void setContextVariables(final Global ctxtGlobal, final ScriptContext ctxt) {
|
||||
// set "context" global variable via contextProperty - because this
|
||||
// property is non-writable
|
||||
contextProperty.setValue(ctxtGlobal, ctxtGlobal, ctxt, false);
|
||||
Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), ctxtGlobal);
|
||||
if (args == null || args == UNDEFINED) {
|
||||
args = ScriptRuntime.EMPTY_ARRAY;
|
||||
}
|
||||
// if no arguments passed, expose it
|
||||
if (! (args instanceof ScriptObject)) {
|
||||
args = ctxtGlobal.wrapAsObject(args);
|
||||
ctxtGlobal.set("arguments", args, false);
|
||||
}
|
||||
}
|
||||
|
||||
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
|
||||
name.getClass(); // null check
|
||||
|
||||
@ -533,11 +438,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
|
||||
final ScriptFunction script = mgcs.getFunction(ctxtGlobal);
|
||||
|
||||
// set ScriptContext variables if ctxt is non-null
|
||||
if (ctxt != null) {
|
||||
setContextVariables(ctxtGlobal, ctxt);
|
||||
}
|
||||
ctxtGlobal.setScriptContext(ctxt);
|
||||
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e, ctxtGlobal);
|
||||
@ -560,10 +461,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
Context.setGlobal(ctxtGlobal);
|
||||
}
|
||||
|
||||
// set ScriptContext variables if ctxt is non-null
|
||||
if (ctxt != null) {
|
||||
setContextVariables(ctxtGlobal, ctxt);
|
||||
}
|
||||
ctxtGlobal.setScriptContext(ctxt);
|
||||
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e, ctxtGlobal);
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
@ -69,12 +71,15 @@ public final class ScriptUtils {
|
||||
* Create a wrapper function that calls {@code func} synchronized on {@code sync} or, if that is undefined,
|
||||
* {@code self}. Used to implement "sync" function in resources/mozilla_compat.js.
|
||||
*
|
||||
* @param func the function to invoke
|
||||
* @param func the function to wrap
|
||||
* @param sync the object to synchronize on
|
||||
* @return a synchronizing wrapper function
|
||||
*/
|
||||
public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
|
||||
return func.makeSynchronizedFunction(sync);
|
||||
public static Object makeSynchronizedFunction(final Object func, final Object sync) {
|
||||
if (func instanceof ScriptFunction) {
|
||||
return ((ScriptFunction)func).makeSynchronizedFunction(sync);
|
||||
}
|
||||
throw typeError("not.a.function", ScriptRuntime.safeToString(func));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This script file is executed by script engine at the construction
|
||||
* of the every new Global object. The functions here assume global variables
|
||||
* "context" of type javax.script.ScriptContext and "engine" of the type
|
||||
* jdk.nashorn.api.scripting.NashornScriptEngine.
|
||||
**/
|
||||
|
||||
Object.defineProperty(this, "__noSuchProperty__", {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: function (name) {
|
||||
'use strict';
|
||||
return engine.__noSuchProperty__(this, context, name);
|
||||
}
|
||||
});
|
||||
|
||||
function print() {
|
||||
var writer = context != null? context.writer : engine.context.writer;
|
||||
if (! (writer instanceof java.io.PrintWriter)) {
|
||||
writer = new java.io.PrintWriter(writer);
|
||||
}
|
||||
|
||||
var buf = new java.lang.StringBuilder();
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (i != 0) {
|
||||
buf.append(' ');
|
||||
}
|
||||
buf.append(String(arguments[i]));
|
||||
}
|
||||
writer.println(buf.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* This is C-like printf
|
||||
*
|
||||
* @param format string to format the rest of the print items
|
||||
* @param args variadic argument list
|
||||
*/
|
||||
Object.defineProperty(this, "printf", {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: function (format, args/*, more args*/) {
|
||||
print(sprintf.apply(this, arguments));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* This is C-like sprintf
|
||||
*
|
||||
* @param format string to format the rest of the print items
|
||||
* @param args variadic argument list
|
||||
*/
|
||||
Object.defineProperty(this, "sprintf", {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: function (format, args/*, more args*/) {
|
||||
var len = arguments.length - 1;
|
||||
var array = [];
|
||||
|
||||
if (len < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (arguments[i+1] instanceof Date) {
|
||||
array[i] = arguments[i+1].getTime();
|
||||
} else {
|
||||
array[i] = arguments[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
array = Java.to(array);
|
||||
return Packages.jdk.nashorn.api.scripting.ScriptUtils.format(format, array);
|
||||
}
|
||||
});
|
@ -1317,20 +1317,14 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
|
||||
// Load up self (scope).
|
||||
method.loadCompilerConstant(SCOPE);
|
||||
final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
|
||||
final List<Expression> evalArgs = callNode.getEvalArgs().getArgs();
|
||||
// load evaluated code
|
||||
loadExpressionAsObject(evalArgs.getCode());
|
||||
loadExpressionAsObject(evalArgs.get(0));
|
||||
// load second and subsequent args for side-effect
|
||||
final List<Expression> callArgs = callNode.getArgs();
|
||||
final int numArgs = callArgs.size();
|
||||
final int numArgs = evalArgs.size();
|
||||
for (int i = 1; i < numArgs; i++) {
|
||||
loadExpressionUnbounded(callArgs.get(i)).pop();
|
||||
loadAndDiscard(evalArgs.get(i));
|
||||
}
|
||||
// special/extra 'eval' arguments
|
||||
loadExpressionUnbounded(evalArgs.getThis());
|
||||
method.load(evalArgs.getLocation());
|
||||
method.load(evalArgs.getStrictMode());
|
||||
method.convert(Type.OBJECT);
|
||||
method._goto(invoke_direct_eval);
|
||||
|
||||
method.label(is_not_eval);
|
||||
@ -1339,7 +1333,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
// This is some scope 'eval' or global eval replaced by user
|
||||
// but not the built-in ECMAScript 'eval' function call
|
||||
method.loadNull();
|
||||
argsCount = loadArgs(callArgs);
|
||||
argsCount = loadArgs(callNode.getArgs());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1349,6 +1343,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
method._goto(eval_done);
|
||||
|
||||
method.label(invoke_direct_eval);
|
||||
// Special/extra 'eval' arguments. These can be loaded late (in consumeStack) as we know none of
|
||||
// them can ever be optimistic.
|
||||
method.loadCompilerConstant(THIS);
|
||||
method.load(callNode.getEvalArgs().getLocation());
|
||||
method.load(CodeGenerator.this.lc.getCurrentFunction().isStrict());
|
||||
// direct call to Global.directEval
|
||||
globalDirectEval();
|
||||
convertOptimisticReturnValue();
|
||||
@ -4438,7 +4437,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
|
||||
private MethodEmitter globalDirectEval() {
|
||||
return method.invokestatic(GLOBAL_OBJECT, "directEval",
|
||||
methodDescriptor(Object.class, Object.class, Object.class, Object.class, Object.class, Object.class));
|
||||
methodDescriptor(Object.class, Object.class, Object.class, Object.class, Object.class, boolean.class));
|
||||
}
|
||||
|
||||
private abstract class OptimisticOperation {
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.codegen;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
|
||||
import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -603,13 +602,11 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Lo
|
||||
|
||||
// 'eval' call with at least one argument
|
||||
if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) {
|
||||
final FunctionNode currentFunction = lc.getCurrentFunction();
|
||||
return callNode.setEvalArgs(
|
||||
new CallNode.EvalArgs(
|
||||
(Expression)ensureUniqueNamesIn(args.get(0)).accept(this),
|
||||
compilerConstant(THIS),
|
||||
evalLocation(callee),
|
||||
currentFunction.isStrict()));
|
||||
final List<Expression> evalArgs = new ArrayList<>(args.size());
|
||||
for(final Expression arg: args) {
|
||||
evalArgs.add((Expression)ensureUniqueNamesIn(arg).accept(this));
|
||||
}
|
||||
return callNode.setEvalArgs(new CallNode.EvalArgs(evalArgs, evalLocation(callee)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,61 +65,35 @@ public final class CallNode extends LexicalContextExpression implements Optimist
|
||||
* Arguments to be passed to builtin {@code eval} function
|
||||
*/
|
||||
public static class EvalArgs {
|
||||
/** evaluated code */
|
||||
private final Expression code;
|
||||
|
||||
/** 'this' passed to evaluated code */
|
||||
private final IdentNode evalThis;
|
||||
private final List<Expression> args;
|
||||
|
||||
/** location string for the eval call */
|
||||
private final String location;
|
||||
|
||||
/** is this call from a strict context? */
|
||||
private final boolean strictMode;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param code code to evaluate
|
||||
* @param evalThis this node
|
||||
* @param location location for the eval call
|
||||
* @param strictMode is this a call from a strict context?
|
||||
* @param args arguments to eval
|
||||
* @param location location for the eval call
|
||||
*/
|
||||
public EvalArgs(final Expression code, final IdentNode evalThis, final String location, final boolean strictMode) {
|
||||
this.code = code;
|
||||
this.evalThis = evalThis;
|
||||
public EvalArgs(final List<Expression> args, final String location) {
|
||||
this.args = args;
|
||||
this.location = location;
|
||||
this.strictMode = strictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the code that is to be eval:ed by this eval function
|
||||
* @return code as an AST node
|
||||
*/
|
||||
public Expression getCode() {
|
||||
return code;
|
||||
public List<Expression> getArgs() {
|
||||
return Collections.unmodifiableList(args);
|
||||
}
|
||||
|
||||
private EvalArgs setCode(final Expression code) {
|
||||
if (this.code == code) {
|
||||
private EvalArgs setArgs(final List<Expression> args) {
|
||||
if (this.args == args) {
|
||||
return this;
|
||||
}
|
||||
return new EvalArgs(code, evalThis, location, strictMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@code this} symbol used to invoke this eval call
|
||||
* @return the {@code this} symbol
|
||||
*/
|
||||
public IdentNode getThis() {
|
||||
return this.evalThis;
|
||||
}
|
||||
|
||||
private EvalArgs setThis(final IdentNode evalThis) {
|
||||
if (this.evalThis == evalThis) {
|
||||
return this;
|
||||
}
|
||||
return new EvalArgs(code, evalThis, location, strictMode);
|
||||
return new EvalArgs(args, location);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,14 +103,6 @@ public final class CallNode extends LexicalContextExpression implements Optimist
|
||||
public String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this eval call is executed in strict mode
|
||||
* @return true if executed in strict mode, false otherwise
|
||||
*/
|
||||
public boolean getStrictMode() {
|
||||
return this.strictMode;
|
||||
}
|
||||
}
|
||||
|
||||
/** arguments for 'eval' call. Non-null only if this call node is 'eval' */
|
||||
@ -212,8 +178,7 @@ public final class CallNode extends LexicalContextExpression implements Optimist
|
||||
setArgs(Node.accept(visitor, Expression.class, args)).
|
||||
setEvalArgs(evalArgs == null ?
|
||||
null :
|
||||
evalArgs.setCode((Expression)evalArgs.getCode().accept(visitor)).
|
||||
setThis((IdentNode)evalArgs.getThis().accept(visitor))));
|
||||
evalArgs.setArgs(Node.accept(visitor, Expression.class, evalArgs.getArgs()))));
|
||||
// Theoretically, we'd need to instead pass lc to every setter and do a replacement on each. In practice,
|
||||
// setType from TypeOverride can't accept a lc, and we don't necessarily want to go there now.
|
||||
if (this != newCallNode) {
|
||||
|
@ -27,6 +27,7 @@ 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.referenceError;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
@ -45,8 +46,11 @@ import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.codegen.ApplySpecialization;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.lookup.Lookup;
|
||||
@ -107,6 +111,10 @@ public final class Global extends ScriptObject implements Scope {
|
||||
/** 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);
|
||||
|
||||
/** Nashorn extension: arguments array */
|
||||
@Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
|
||||
public Object arguments;
|
||||
|
||||
/** ECMA 15.1.2.2 parseInt (string , radix) */
|
||||
@Property(attributes = Attribute.NOT_ENUMERABLE)
|
||||
public Object parseInt;
|
||||
@ -411,12 +419,13 @@ public final class Global extends ScriptObject implements Scope {
|
||||
// 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);
|
||||
private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class);
|
||||
private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class);
|
||||
private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class);
|
||||
private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class);
|
||||
private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class);
|
||||
private static final MethodHandle 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);
|
||||
@ -427,6 +436,20 @@ public final class Global extends ScriptObject implements Scope {
|
||||
// context to which this global belongs to
|
||||
private final Context context;
|
||||
|
||||
// current ScriptContext to use - can be null.
|
||||
private ScriptContext scontext;
|
||||
// associated Property object for "context" property.
|
||||
private jdk.nashorn.internal.runtime.Property scontextProperty;
|
||||
|
||||
/**
|
||||
* Set the current script context
|
||||
* @param scontext script context
|
||||
*/
|
||||
public void setScriptContext(final ScriptContext scontext) {
|
||||
this.scontext = scontext;
|
||||
scontextProperty.setValue(this, this, scontext, false);
|
||||
}
|
||||
|
||||
// global constants for this global - they can be replaced with MethodHandle.constant until invalidated
|
||||
private static AtomicReference<GlobalConstants> gcsInstance = new AtomicReference<>();
|
||||
|
||||
@ -447,12 +470,7 @@ public final class Global extends ScriptObject implements Scope {
|
||||
// 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();
|
||||
return $nasgenmap$;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -483,6 +501,10 @@ public final class Global extends ScriptObject implements Scope {
|
||||
return global;
|
||||
}
|
||||
|
||||
private static Global instanceFrom(final Object self) {
|
||||
return self instanceof Global? (Global)self : instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the global constants map for fields that
|
||||
* can be accessed as MethodHandle.constant
|
||||
@ -542,13 +564,13 @@ public final class Global extends ScriptObject implements Scope {
|
||||
* as well as our extension builtin objects like "Java", "JSAdapter" as properties
|
||||
* of the global scope object.
|
||||
*/
|
||||
public void initBuiltinObjects() {
|
||||
public void initBuiltinObjects(final ScriptEngine engine) {
|
||||
if (this.builtinObject != null) {
|
||||
// already initialized, just return
|
||||
return;
|
||||
}
|
||||
|
||||
init();
|
||||
init(engine);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -848,6 +870,32 @@ public final class Global extends ScriptObject implements Scope {
|
||||
return getLazilyCreatedValue(key, creator, dynamicInvokers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to search missing variables in ScriptContext if available
|
||||
* @param self used to detect if scope call or not (this function is 'strict')
|
||||
* @param name name of the variable missing
|
||||
* @return value of the missing variable or undefined (or TypeError for scope search)
|
||||
*/
|
||||
public static Object __noSuchProperty__(final Object self, final Object name) {
|
||||
final Global global = Global.instance();
|
||||
final ScriptContext sctxt = global.scontext;
|
||||
final String nameStr = name.toString();
|
||||
|
||||
if (sctxt != null) {
|
||||
final int scope = sctxt.getAttributesScope(nameStr);
|
||||
if (scope != -1) {
|
||||
return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global);
|
||||
}
|
||||
}
|
||||
|
||||
if (self == UNDEFINED) {
|
||||
// scope access and so throw ReferenceError
|
||||
throw referenceError(global, "not.defined", nameStr);
|
||||
}
|
||||
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the eval used when 'indirect' eval call is made.
|
||||
*
|
||||
@ -860,7 +908,7 @@ public final class Global extends ScriptObject implements Scope {
|
||||
* @return the result of eval
|
||||
*/
|
||||
public static Object eval(final Object self, final Object str) {
|
||||
return directEval(self, str, UNDEFINED, UNDEFINED, UNDEFINED);
|
||||
return directEval(self, str, UNDEFINED, UNDEFINED, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -876,14 +924,14 @@ public final class Global extends ScriptObject implements Scope {
|
||||
*
|
||||
* 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) {
|
||||
public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) {
|
||||
if (!(str instanceof String || str instanceof ConsString)) {
|
||||
return str;
|
||||
}
|
||||
final Global global = Global.instance();
|
||||
final Global global = Global.instanceFrom(self);
|
||||
final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
|
||||
|
||||
return global.getContext().eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict), true);
|
||||
return global.getContext().eval(scope, str.toString(), callThis, location, strict, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -895,7 +943,7 @@ public final class Global extends ScriptObject implements Scope {
|
||||
* @return result of print (undefined)
|
||||
*/
|
||||
public static Object print(final Object self, final Object... objects) {
|
||||
return printImpl(false, objects);
|
||||
return Global.instanceFrom(self).printImpl(false, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -907,7 +955,7 @@ public final class Global extends ScriptObject implements Scope {
|
||||
* @return result of println (undefined)
|
||||
*/
|
||||
public static Object println(final Object self, final Object... objects) {
|
||||
return printImpl(true, objects);
|
||||
return Global.instanceFrom(self).printImpl(true, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -921,7 +969,7 @@ public final class Global extends ScriptObject implements Scope {
|
||||
* @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 Global global = Global.instanceFrom(self);
|
||||
final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
|
||||
return global.getContext().load(scope, source);
|
||||
}
|
||||
@ -937,7 +985,7 @@ public final class Global extends ScriptObject implements Scope {
|
||||
* @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 Global global = Global.instanceFrom(self);
|
||||
final int length = args.length;
|
||||
final boolean hasArgs = 0 < length;
|
||||
final Object from = hasArgs ? args[0] : UNDEFINED;
|
||||
@ -1604,7 +1652,7 @@ public final class Global extends ScriptObject implements Scope {
|
||||
splitState = state;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
private void init(final ScriptEngine engine) {
|
||||
assert Context.getGlobal() == this : "this global is not set as current";
|
||||
|
||||
final ScriptEnvironment env = getContext().getEnv();
|
||||
@ -1705,12 +1753,19 @@ public final class Global extends ScriptObject implements Scope {
|
||||
copyBuiltins();
|
||||
|
||||
// expose script (command line) arguments as "arguments" property of global
|
||||
final Object argumentsObject = wrapAsObject(env.getArguments().toArray());
|
||||
final int argumentsFlags = Attribute.NOT_ENUMERABLE;
|
||||
addOwnProperty("arguments", argumentsFlags, argumentsObject);
|
||||
arguments = wrapAsObject(env.getArguments().toArray());
|
||||
if (env._scripting) {
|
||||
// synonym for "arguments" in scripting mode
|
||||
addOwnProperty("$ARG", argumentsFlags, argumentsObject);
|
||||
addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments);
|
||||
}
|
||||
|
||||
if (engine != null) {
|
||||
final int NOT_ENUMERABLE_NOT_CONFIG = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE;
|
||||
scontextProperty = addOwnProperty("context", NOT_ENUMERABLE_NOT_CONFIG, null);
|
||||
addOwnProperty("engine", NOT_ENUMERABLE_NOT_CONFIG, engine);
|
||||
// __noSuchProperty__ hook for ScriptContext search of missing variables
|
||||
final ScriptFunction noSuchProp = ScriptFunctionImpl.makeStrictFunction(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY);
|
||||
addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1878,8 +1933,8 @@ public final class Global extends ScriptObject implements Scope {
|
||||
this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug"));
|
||||
}
|
||||
|
||||
private static Object printImpl(final boolean newLine, final Object... objects) {
|
||||
final PrintWriter out = Global.getEnv().getOut();
|
||||
private Object printImpl(final boolean newLine, final Object... objects) {
|
||||
final PrintWriter out = scontext != null? new PrintWriter(scontext.getWriter()) : getContext().getEnv().getOut();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final Object object : objects) {
|
||||
@ -2023,12 +2078,11 @@ public final class Global extends ScriptObject implements Scope {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
final Object value = ObjectPrototype.get(key);
|
||||
if (value instanceof ScriptFunction) {
|
||||
final ScriptFunction func = (ScriptFunction)value;
|
||||
final ScriptObject prototype = ScriptFunction.getPrototype(func);
|
||||
|
@ -222,7 +222,6 @@ public final class NativeDebug extends ScriptObject {
|
||||
out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
|
||||
out.println("PropertyMap count " + PropertyMap.getCount());
|
||||
out.println("PropertyMap cloned " + PropertyMap.getClonedCount());
|
||||
out.println("PropertyMap duplicated " + PropertyMap.getDuplicatedCount());
|
||||
out.println("PropertyMap history hit " + PropertyMap.getHistoryHit());
|
||||
out.println("PropertyMap proto invalidations " + PropertyMap.getProtoInvalidations());
|
||||
out.println("PropertyMap proto history hit " + PropertyMap.getProtoHistoryHit());
|
||||
|
@ -36,6 +36,7 @@ import java.util.List;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.support.TypeUtilities;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.api.scripting.ScriptUtils;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
import jdk.nashorn.internal.objects.annotations.Function;
|
||||
import jdk.nashorn.internal.objects.annotations.ScriptClass;
|
||||
@ -45,6 +46,7 @@ import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ListAdapter;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
|
||||
@ -79,6 +81,73 @@ public final class NativeJava {
|
||||
return type instanceof StaticClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns synchronized wrapper version of the given ECMAScript function.
|
||||
* @param self not used
|
||||
* @param func the ECMAScript function whose synchronized version is returned.
|
||||
* @param obj the object (i.e, lock) on which the function synchronizes.
|
||||
* @return synchronized wrapper version of the given ECMAScript function.
|
||||
*/
|
||||
@Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static Object synchronizedFunc(final Object self, final Object func, final Object obj) {
|
||||
return ScriptUtils.makeSynchronizedFunction(func, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified object is a Java method.
|
||||
* @param self not used
|
||||
* @param obj the object that is checked if it is a Java method object or not
|
||||
* @return tells whether given object is a Java method object or not.
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static boolean isJavaMethod(final Object self, final Object obj) {
|
||||
return Bootstrap.isDynamicMethod(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified object is a java function (but not script function)
|
||||
* @param self not used
|
||||
* @param obj the object that is checked if it is a Java function or not
|
||||
* @return tells whether given object is a Java function or not
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static boolean isJavaFunction(final Object self, final Object obj) {
|
||||
return Bootstrap.isCallable(obj) && !(obj instanceof ScriptFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified object is a Java object but not a script object
|
||||
* @param self not used
|
||||
* @param obj the object that is checked
|
||||
* @return tells whether given object is a Java object but not a script object
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static boolean isJavaObject(final Object self, final Object obj) {
|
||||
return obj != null && !(obj instanceof ScriptObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified object is a ECMAScript object, that is an instance of {@link ScriptObject}.
|
||||
* @param self not used
|
||||
* @param obj the object that is checked if it is a ECMAScript object or not
|
||||
* @return tells whether given object is a ECMAScript object or not.
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static boolean isScriptObject(final Object self, final Object obj) {
|
||||
return obj instanceof ScriptObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified object is a ECMAScript function, that is an instance of {@link ScriptFunction}.
|
||||
* @param self not used
|
||||
* @param obj the object that is checked if it is a ECMAScript function or not
|
||||
* @return tells whether given object is a ECMAScript function or not.
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static boolean isScriptFunction(final Object self, final Object obj) {
|
||||
return obj instanceof ScriptFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects
|
||||
|
@ -184,6 +184,15 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
return new AnonymousFunction();
|
||||
}
|
||||
|
||||
private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final int flags) {
|
||||
final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, flags);
|
||||
func.setPrototype(UNDEFINED);
|
||||
// Non-constructor built-in functions do not have "prototype" property
|
||||
func.deleteOwnProperty(func.getMap().findProperty("prototype"));
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for non-constructor built-in functions
|
||||
*
|
||||
@ -193,12 +202,18 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
* @return new ScriptFunction
|
||||
*/
|
||||
static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) {
|
||||
final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, ScriptFunctionData.IS_BUILTIN);
|
||||
func.setPrototype(UNDEFINED);
|
||||
// Non-constructor built-in functions do not have "prototype" property
|
||||
func.deleteOwnProperty(func.getMap().findProperty("prototype"));
|
||||
return makeFunction(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
|
||||
}
|
||||
|
||||
return func;
|
||||
/**
|
||||
* Factory method for non-constructor built-in, strict functions
|
||||
*
|
||||
* @param name function name
|
||||
* @param methodHandle handle for invocation
|
||||
* @return new ScriptFunction
|
||||
*/
|
||||
static ScriptFunction makeStrictFunction(final String name, final MethodHandle methodHandle) {
|
||||
return makeFunction(name, methodHandle, null, ScriptFunctionData.IS_BUILTIN | ScriptFunctionData.IS_STRICT );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,6 +62,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import javax.script.ScriptEngine;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
@ -954,16 +955,17 @@ public final class Context {
|
||||
* Initialize given global scope object.
|
||||
*
|
||||
* @param global the global
|
||||
* @param engine the associated ScriptEngine instance, can be null
|
||||
* @return the initialized global scope object.
|
||||
*/
|
||||
public Global initGlobal(final Global global) {
|
||||
public Global initGlobal(final Global global, final ScriptEngine engine) {
|
||||
// Need only minimal global object, if we are just compiling.
|
||||
if (!env._compile_only) {
|
||||
final Global oldGlobal = Context.getGlobal();
|
||||
try {
|
||||
Context.setGlobal(global);
|
||||
// initialize global scope with builtin global objects
|
||||
global.initBuiltinObjects();
|
||||
global.initBuiltinObjects(engine);
|
||||
} finally {
|
||||
Context.setGlobal(oldGlobal);
|
||||
}
|
||||
@ -972,6 +974,16 @@ public final class Context {
|
||||
return global;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize given global scope object.
|
||||
*
|
||||
* @param global the global
|
||||
* @return the initialized global scope object.
|
||||
*/
|
||||
public Global initGlobal(final Global global) {
|
||||
return initGlobal(global, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current global's context
|
||||
* @return current global's context
|
||||
|
@ -405,12 +405,8 @@ public final class ECMAErrors {
|
||||
// Look for script package in class name (into which compiler puts generated code)
|
||||
if (className.startsWith(scriptPackage) && !CompilerConstants.isInternalMethodName(frame.getMethodName())) {
|
||||
final String source = frame.getFileName();
|
||||
/*
|
||||
* Make sure that it is not some Java code that Nashorn has in that package!
|
||||
* also, we don't want to report JavaScript code that lives in script engine implementation
|
||||
* We want to report only user's own scripts and not any of our own scripts like "engine.js"
|
||||
*/
|
||||
return source != null && !source.endsWith(".java") && !source.contains(NashornException.ENGINE_SCRIPT_SOURCE_NAME);
|
||||
// Make sure that it is not some Java code that Nashorn has in that package!
|
||||
return source != null && !source.endsWith(".java");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -145,21 +145,6 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
|
||||
this(propertyMap, propertyMap.properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates this PropertyMap instance. This is used to duplicate 'shared'
|
||||
* maps {@link PropertyMap} used as process wide singletons. Shared maps are
|
||||
* duplicated for every global scope object. That way listeners, proto and property
|
||||
* histories are scoped within a global scope.
|
||||
*
|
||||
* @return Duplicated {@link PropertyMap}.
|
||||
*/
|
||||
public PropertyMap duplicate() {
|
||||
if (Context.DEBUG) {
|
||||
duplicatedCount++;
|
||||
}
|
||||
return new PropertyMap(this.properties, this.className, 0, 0, 0, containsArrayKeys());
|
||||
}
|
||||
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
out.writeObject(properties.getProperties());
|
||||
@ -968,7 +953,6 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
|
||||
// counters updated only in debug mode
|
||||
private static int count;
|
||||
private static int clonedCount;
|
||||
private static int duplicatedCount;
|
||||
private static int historyHit;
|
||||
private static int protoInvalidations;
|
||||
private static int protoHistoryHit;
|
||||
@ -988,13 +972,6 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
|
||||
return clonedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of maps that are duplicated.
|
||||
*/
|
||||
public static int getDuplicatedCount() {
|
||||
return duplicatedCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of times history was successfully used.
|
||||
*/
|
||||
|
@ -103,10 +103,10 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
public static final String PROTO_PROPERTY_NAME = "__proto__";
|
||||
|
||||
/** Search fall back routine name for "no such method" */
|
||||
static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__";
|
||||
public static final String NO_SUCH_METHOD_NAME = "__noSuchMethod__";
|
||||
|
||||
/** Search fall back routine name for "no such property" */
|
||||
static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
|
||||
public static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
|
||||
|
||||
/** Per ScriptObject flag - is this a scope object? */
|
||||
public static final int IS_SCOPE = 1 << 0;
|
||||
@ -160,7 +160,8 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
static final MethodHandle GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
|
||||
|
||||
private static final MethodHandle TRUNCATINGFILTER = findOwnMH_S("truncatingFilter", Object[].class, int.class, Object[].class);
|
||||
private static final MethodHandle KNOWNFUNCPROPGUARD = findOwnMH_S("knownFunctionPropertyGuard", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, Object.class, ScriptFunction.class);
|
||||
private static final MethodHandle KNOWNFUNCPROPGUARDSELF = findOwnMH_S("knownFunctionPropertyGuardSelf", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, ScriptFunction.class);
|
||||
private static final MethodHandle KNOWNFUNCPROPGUARDPROTO = findOwnMH_S("knownFunctionPropertyGuardProto", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, int.class, ScriptFunction.class);
|
||||
|
||||
private static final ArrayList<MethodHandle> PROTO_FILTERS = new ArrayList<>();
|
||||
|
||||
@ -2271,13 +2272,20 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
if (scopeAccess && func.isStrict()) {
|
||||
mh = bindTo(mh, UNDEFINED);
|
||||
}
|
||||
|
||||
return new GuardedInvocation(
|
||||
mh,
|
||||
//TODO this always does a scriptobject check
|
||||
getKnownFunctionPropertyGuard(
|
||||
find.isSelf()?
|
||||
getKnownFunctionPropertyGuardSelf(
|
||||
getMap(),
|
||||
find.getGetter(Object.class, INVALID_PROGRAM_POINT),
|
||||
find.getOwner(),
|
||||
func)
|
||||
:
|
||||
//TODO this always does a scriptobject check
|
||||
getKnownFunctionPropertyGuardProto(
|
||||
getMap(),
|
||||
find.getGetter(Object.class, INVALID_PROGRAM_POINT),
|
||||
find.getProtoChainLength(),
|
||||
func),
|
||||
getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
|
||||
//TODO this doesn't need a ClassCastException as guard always checks script object
|
||||
@ -3595,15 +3603,51 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
return MH.findStatic(MethodHandles.lookup(), ScriptObject.class, name, MH.type(rtype, types));
|
||||
}
|
||||
|
||||
private static MethodHandle getKnownFunctionPropertyGuard(final PropertyMap map, final MethodHandle getter, final Object where, final ScriptFunction func) {
|
||||
return MH.insertArguments(KNOWNFUNCPROPGUARD, 1, map, getter, where, func);
|
||||
private static MethodHandle getKnownFunctionPropertyGuardSelf(final PropertyMap map, final MethodHandle getter, final ScriptFunction func) {
|
||||
return MH.insertArguments(KNOWNFUNCPROPGUARDSELF, 1, map, getter, func);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean knownFunctionPropertyGuard(final Object self, final PropertyMap map, final MethodHandle getter, final Object where, final ScriptFunction func) {
|
||||
private static boolean knownFunctionPropertyGuardSelf(final Object self, final PropertyMap map, final MethodHandle getter, final ScriptFunction func) {
|
||||
if (self instanceof ScriptObject && ((ScriptObject)self).getMap() == map) {
|
||||
try {
|
||||
return getter.invokeExact(where) == func;
|
||||
return getter.invokeExact(self) == func;
|
||||
} catch (final RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (final Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static MethodHandle getKnownFunctionPropertyGuardProto(final PropertyMap map, final MethodHandle getter, final int depth, final ScriptFunction func) {
|
||||
return MH.insertArguments(KNOWNFUNCPROPGUARDPROTO, 1, map, getter, depth, func);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static ScriptObject getProto(final ScriptObject self, final int depth) {
|
||||
ScriptObject proto = self;
|
||||
for (int d = 0; d < depth; d++) {
|
||||
proto = proto.getProto();
|
||||
if (proto == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean knownFunctionPropertyGuardProto(final Object self, final PropertyMap map, final MethodHandle getter, final int depth, final ScriptFunction func) {
|
||||
if (self instanceof ScriptObject && ((ScriptObject)self).getMap() == map) {
|
||||
final ScriptObject proto = getProto((ScriptObject)self, depth);
|
||||
if (proto == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return getter.invokeExact((Object)proto) == func;
|
||||
} catch (final RuntimeException | Error e) {
|
||||
throw e;
|
||||
} catch (final Throwable t) {
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import java.util.Objects;
|
||||
import jdk.internal.dynalink.beans.BeansLinker;
|
||||
|
||||
/**
|
||||
@ -48,4 +49,9 @@ final class BoundDynamicMethod {
|
||||
Object getBoundThis() {
|
||||
return boundThis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return dynamicMethod.toString() + " on " + Objects.toString(boundThis);
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ makeFuncAndCall("switch(0) { default: {break;} return }");
|
||||
makeFuncAndCall("L: { { break L; } return; }");
|
||||
makeFuncAndCall("L: { while(0) break L; return; }");
|
||||
makeFuncExpectError("L: {while(0) break L; return [](); }", TypeError);
|
||||
// makeFuncAndCall("do with({}) break ; while(0);");
|
||||
makeFuncAndCall("do with({}) break ; while(0);");
|
||||
makeFuncAndCall("while(0) with({}) continue ;");
|
||||
makeFuncAndCall("eval([]);");
|
||||
makeFuncAndCall("try{} finally{[]}");
|
||||
@ -59,10 +59,10 @@ makeFuncAndCall("Error() * (false)[-0]--");
|
||||
makeFuncAndCall("try { var x = 1, x = null; } finally { }");
|
||||
makeFuncAndCall("try { var x = {}, x = []; } catch(x3) { }");
|
||||
makeFuncAndCall("[delete this]");
|
||||
// makeFuncAndCall("if(eval('', eval('', function() {}))) { }");
|
||||
// makeFuncAndCall("if(eval('', eval('', function() {}))) { }");
|
||||
// makeFuncAndCall("eval(\"[,,];\", [11,12,13,14].some)");
|
||||
// makeFuncAndCall("eval(\"1.2e3\", ({})[ /x/ ])");
|
||||
makeFuncAndCall("if(eval('', eval('', function() {}))) { }");
|
||||
makeFuncAndCall("if(eval('', eval('', function() {}))) { }");
|
||||
makeFuncAndCall("eval(\"[,,];\", [11,12,13,14].some)");
|
||||
makeFuncAndCall("eval(\"1.2e3\", ({})[ /x/ ])");
|
||||
makeFuncExpectError("eval(\"x4\", x3);", ReferenceError);
|
||||
makeFuncAndCall("with({5.0000000000000000000000: String()}){(false); }");
|
||||
makeFuncAndCall("try { var x = undefined, x = 5.0000000000000000000000; } catch(x) { x = undefined; }");
|
||||
@ -72,4 +72,4 @@ makeFuncAndCall("(false % !this) && 0");
|
||||
makeFuncAndCall("with({8: 'fafafa'.replace()}){ }");
|
||||
makeFuncAndCall("(function (x) '' )(true)");
|
||||
makeFuncExpectError("new eval(function(){})", TypeError);
|
||||
//** makeFuncAndCall('eval("23", ({})[/x/])');
|
||||
makeFuncAndCall('eval("23", ({})[/x/])');
|
||||
|
36
nashorn/test/script/basic/JDK-8047067.js
Normal file
36
nashorn/test/script/basic/JDK-8047067.js
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2014, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8047067: all eval arguments need to be copied in Lower
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
// The second expression triggers optimistic deoptimization, and if not
|
||||
// all eval arguments were copied in Lower, we'd end up with duplicate
|
||||
// program points that'd cause incorrect continuation program point in
|
||||
// the rest-of, and therefore a bad stack, and therefore an AIOOBE in
|
||||
// the continuation setup code.
|
||||
eval("23", ({})[/x/])
|
144
nashorn/test/script/basic/JDK-8049086.js
Normal file
144
nashorn/test/script/basic/JDK-8049086.js
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8049086: Minor API convenience functions on "Java" object
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
var System = Java.type("java.lang.System");
|
||||
var out = System.out;
|
||||
var println = out.println;
|
||||
var getProperty = System.getProperty;
|
||||
var File = Java.type("java.io.File")["(String)"];
|
||||
|
||||
print("println is java method? " + Java.isJavaMethod(println));
|
||||
print("println is script function? " + Java.isScriptFunction(println));
|
||||
print("getProperty is java method? " + Java.isJavaMethod(getProperty));
|
||||
print("getProperty is script function? " + Java.isScriptFunction(getProperty));
|
||||
print("File is java method? " + Java.isJavaMethod(File));
|
||||
print("File is script function? " + Java.isScriptFunction(File));
|
||||
|
||||
print("eval is script function? " + Java.isScriptFunction(eval));
|
||||
print("eval is java method? " + Java.isJavaMethod(eval));
|
||||
function hello() {}
|
||||
print("hello is script function? " + Java.isScriptFunction(hello));
|
||||
print("hello is java method? " + Java.isJavaMethod(hello));
|
||||
|
||||
print("out is script object? " + Java.isScriptObject(out));
|
||||
print("System is script object? " + Java.isScriptObject(System));
|
||||
print("Object is script object? " + Java.isScriptObject(Object));
|
||||
print("{} is script object? " + Java.isScriptObject({}));
|
||||
print("/foo/ is script object? " + Java.isScriptObject(/foo/));
|
||||
|
||||
// Java function is anything whose 'typeof' is 'function' but it is not
|
||||
// a script function! This includes:
|
||||
// (a) Java methods (b) Java classes (as these respond to new)
|
||||
// (c) FunctionalInterface objects (d) JSObjects that are 'functions'
|
||||
|
||||
print("java.awt.Color is java function? " + Java.isJavaFunction(java.awt.Color));
|
||||
print("java.lang.Runnable instance is java function? "
|
||||
+ Java.isJavaFunction(new java.lang.Runnable(function() {})));
|
||||
print("eval is java function? " + Java.isJavaFunction(eval));
|
||||
print("println is java function? " + Java.isJavaFunction(println));
|
||||
print("getProperty is java function? " + Java.isJavaFunction(getProperty));
|
||||
|
||||
var JSObject = Java.type("jdk.nashorn.api.scripting.JSObject");
|
||||
print("callable JSObject is function? " +
|
||||
Java.isJavaFunction(new JSObject() {
|
||||
isFunction: function() true,
|
||||
call: function() {}
|
||||
})
|
||||
);
|
||||
|
||||
print("Non callable JSObject is function? " +
|
||||
Java.isJavaFunction(new JSObject() {
|
||||
isFunction: function() false,
|
||||
})
|
||||
);
|
||||
|
||||
// synchronized function
|
||||
var lock = new java.lang.Object();
|
||||
|
||||
print("lock is java object? " + Java.isJavaObject(lock));
|
||||
print("eval is java object? " + Java.isJavaObject(eval));
|
||||
print("{} is java object? " + Java.isJavaObject({}));
|
||||
print("/foo/ is java object? " + Java.isJavaObject(/foo/));
|
||||
print("[] is java object? " + Java.isJavaObject([]));
|
||||
print("java.io.File is java object? " + Java.isJavaObject(java.io.File));
|
||||
|
||||
// synchornized function checks
|
||||
Java.synchronized(function() {
|
||||
var th = new java.lang.Thread(Java.synchronized(function() {
|
||||
print("new thread");
|
||||
print("notifying..");
|
||||
lock.notifyAll();
|
||||
}, lock));
|
||||
th.start();
|
||||
print("about to wait..");
|
||||
lock.wait();
|
||||
th.join();
|
||||
print("done waiting!");
|
||||
}, lock)();
|
||||
|
||||
// try Mozilla "sync" as well
|
||||
load("nashorn:mozilla_compat.js");
|
||||
sync(function() {
|
||||
var th = new java.lang.Thread(sync(function() {
|
||||
print("new thread");
|
||||
print("notifying..");
|
||||
lock.notifyAll();
|
||||
}, lock));
|
||||
th.start();
|
||||
print("about to wait..");
|
||||
lock.wait();
|
||||
th.join();
|
||||
print("done waiting!");
|
||||
}, lock)();
|
||||
|
||||
function expectTypeError(func) {
|
||||
try {
|
||||
func();
|
||||
throw new Error("should have thrown TypeError");
|
||||
} catch (e) {
|
||||
if (! (e instanceof TypeError)) {
|
||||
fail("Expected TypeError, got " +e);
|
||||
}
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
|
||||
expectTypeError(function() Java.synchronized(232));
|
||||
expectTypeError(function() sync(232));
|
||||
expectTypeError(function() Java.synchronized({}));
|
||||
expectTypeError(function() sync({}));
|
||||
expectTypeError(function() Java.synchronized([]));
|
||||
expectTypeError(function() sync([]));
|
||||
expectTypeError(function() Java.synchronized("hello"));
|
||||
expectTypeError(function() sync("hello"));
|
||||
expectTypeError(function() Java.synchronized(null));
|
||||
expectTypeError(function() sync(null));
|
||||
expectTypeError(function() Java.synchronized(undefined));
|
||||
expectTypeError(function() sync(undefined));
|
48
nashorn/test/script/basic/JDK-8049086.js.EXPECTED
Normal file
48
nashorn/test/script/basic/JDK-8049086.js.EXPECTED
Normal file
@ -0,0 +1,48 @@
|
||||
println is java method? true
|
||||
println is script function? false
|
||||
getProperty is java method? true
|
||||
getProperty is script function? false
|
||||
File is java method? true
|
||||
File is script function? false
|
||||
eval is script function? true
|
||||
eval is java method? false
|
||||
hello is script function? true
|
||||
hello is java method? false
|
||||
out is script object? false
|
||||
System is script object? false
|
||||
Object is script object? true
|
||||
{} is script object? true
|
||||
/foo/ is script object? true
|
||||
java.awt.Color is java function? true
|
||||
java.lang.Runnable instance is java function? true
|
||||
eval is java function? false
|
||||
println is java function? true
|
||||
getProperty is java function? true
|
||||
callable JSObject is function? true
|
||||
Non callable JSObject is function? false
|
||||
lock is java object? true
|
||||
eval is java object? false
|
||||
{} is java object? false
|
||||
/foo/ is java object? false
|
||||
[] is java object? false
|
||||
java.io.File is java object? true
|
||||
about to wait..
|
||||
new thread
|
||||
notifying..
|
||||
done waiting!
|
||||
about to wait..
|
||||
new thread
|
||||
notifying..
|
||||
done waiting!
|
||||
TypeError: 232 is not a function
|
||||
TypeError: 232 is not a function
|
||||
TypeError: [object Object] is not a function
|
||||
TypeError: [object Object] is not a function
|
||||
TypeError: [object Array] is not a function
|
||||
TypeError: [object Array] is not a function
|
||||
TypeError: hello is not a function
|
||||
TypeError: hello is not a function
|
||||
TypeError: null is not a function
|
||||
TypeError: null is not a function
|
||||
TypeError: undefined is not a function
|
||||
TypeError: undefined is not a function
|
@ -136,8 +136,7 @@ public class CodeStoreAndPathTest {
|
||||
// Check that a new compiled script is stored in existing code cache
|
||||
e.eval(code1);
|
||||
final DirectoryStream<Path> stream = Files.newDirectoryStream(codeCachePath);
|
||||
// Already one compiled script has been stored in the cache during initialization
|
||||
checkCompiledScripts(stream, 2);
|
||||
checkCompiledScripts(stream, 1);
|
||||
// Setting to default current working dir
|
||||
} finally {
|
||||
System.setProperty("user.dir", oldUserDir);
|
||||
@ -154,9 +153,8 @@ public class CodeStoreAndPathTest {
|
||||
e.eval(code1);
|
||||
e.eval(code2);
|
||||
e.eval(code3);// less than minimum size for storing
|
||||
// Already one compiled script has been stored in the cache during initialization
|
||||
// adding code1 and code2.
|
||||
final DirectoryStream<Path> stream = Files.newDirectoryStream(codeCachePath);
|
||||
checkCompiledScripts(stream, 3);
|
||||
checkCompiledScripts(stream, 2);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user