8041697: CompiledScript slower when eval with binding
Reviewed-by: lagergren, attila, hannesw
This commit is contained in:
parent
f96b4d2e4e
commit
b705fef9d6
@ -525,6 +525,31 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt));
|
||||
}
|
||||
|
||||
private Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
|
||||
final Global oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != ctxtGlobal);
|
||||
try {
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(ctxtGlobal);
|
||||
}
|
||||
|
||||
final ScriptFunction script = mgcs.getFunction(ctxtGlobal);
|
||||
|
||||
// set ScriptContext variables if ctxt is non-null
|
||||
if (ctxt != null) {
|
||||
setContextVariables(ctxtGlobal, ctxt);
|
||||
}
|
||||
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e, ctxtGlobal);
|
||||
throw new AssertionError("should not reach here");
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
|
||||
if (script == null) {
|
||||
return null;
|
||||
@ -571,18 +596,38 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
}
|
||||
|
||||
private CompiledScript asCompiledScript(final Source source) throws ScriptException {
|
||||
final ScriptFunction func = compileImpl(source, context);
|
||||
final Context.MultiGlobalCompiledScript mgcs;
|
||||
final ScriptFunction func;
|
||||
final Global oldGlobal = Context.getGlobal();
|
||||
final Global newGlobal = getNashornGlobalFrom(context);
|
||||
final boolean globalChanged = (oldGlobal != newGlobal);
|
||||
try {
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(newGlobal);
|
||||
}
|
||||
|
||||
mgcs = nashornContext.compileScript(source);
|
||||
func = mgcs.getFunction(newGlobal);
|
||||
} catch (final Exception e) {
|
||||
throwAsScriptException(e, newGlobal);
|
||||
throw new AssertionError("should not reach here");
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
return new CompiledScript() {
|
||||
@Override
|
||||
public Object eval(final ScriptContext ctxt) throws ScriptException {
|
||||
final Global globalObject = getNashornGlobalFrom(ctxt);
|
||||
// Are we running the script in the correct global?
|
||||
// Are we running the script in the same global in which it was compiled?
|
||||
if (func.getScope() == globalObject) {
|
||||
return evalImpl(func, ctxt, globalObject);
|
||||
}
|
||||
// ScriptContext with a different global. Compile again!
|
||||
// Note that we may still hit per-global compilation cache.
|
||||
return evalImpl(compileImpl(source, ctxt), ctxt, globalObject);
|
||||
|
||||
// different global
|
||||
return evalImpl(mgcs, ctxt, globalObject);
|
||||
}
|
||||
@Override
|
||||
public ScriptEngine getEngine() {
|
||||
|
@ -489,6 +489,39 @@ public final class Context {
|
||||
return compileScript(source, scope, this.errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to represent compiled code that can be re-used across many
|
||||
* global scope instances
|
||||
*/
|
||||
public static interface MultiGlobalCompiledScript {
|
||||
/**
|
||||
* Obtain script function object for a specific global scope object.
|
||||
*
|
||||
* @param newGlobal global scope for which function object is obtained
|
||||
* @return script function for script level expressions
|
||||
*/
|
||||
public ScriptFunction getFunction(final Global newGlobal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a top level script.
|
||||
*
|
||||
* @param source the script source
|
||||
* @return reusable compiled script across many global scopes.
|
||||
*/
|
||||
public MultiGlobalCompiledScript compileScript(final Source source) {
|
||||
final Class<?> clazz = compile(source, this.errors, this._strict);
|
||||
final MethodHandle runMethodHandle = getRunScriptHandle(clazz);
|
||||
final boolean strict = isStrict(clazz);
|
||||
|
||||
return new MultiGlobalCompiledScript() {
|
||||
@Override
|
||||
public ScriptFunction getFunction(final Global newGlobal) {
|
||||
return Context.getGlobal().newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, newGlobal, strict);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for {@code eval}
|
||||
*
|
||||
@ -949,14 +982,8 @@ public final class Context {
|
||||
return ScriptRuntime.apply(script, thiz);
|
||||
}
|
||||
|
||||
private static ScriptFunction getRunScriptFunction(final Class<?> script, final ScriptObject scope) {
|
||||
if (script == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get run method - the entry point to the script
|
||||
final MethodHandle runMethodHandle =
|
||||
MH.findStatic(
|
||||
private static MethodHandle getRunScriptHandle(final Class<?> script) {
|
||||
return MH.findStatic(
|
||||
MethodHandles.lookup(),
|
||||
script,
|
||||
RUN_SCRIPT.symbolName(),
|
||||
@ -964,14 +991,24 @@ public final class Context {
|
||||
Object.class,
|
||||
ScriptFunction.class,
|
||||
Object.class));
|
||||
}
|
||||
|
||||
boolean strict;
|
||||
|
||||
private static boolean isStrict(final Class<?> script) {
|
||||
try {
|
||||
strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null);
|
||||
return script.getField(STRICT_MODE.symbolName()).getBoolean(null);
|
||||
} catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
strict = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static ScriptFunction getRunScriptFunction(final Class<?> script, final ScriptObject scope) {
|
||||
if (script == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get run method - the entry point to the script
|
||||
final MethodHandle runMethodHandle = getRunScriptHandle(script);
|
||||
boolean strict = isStrict(script);
|
||||
|
||||
// Package as a JavaScript function and pass function back to shell.
|
||||
return Context.getGlobal().newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
|
||||
|
@ -453,7 +453,7 @@ public class Shell {
|
||||
}
|
||||
} finally {
|
||||
if (globalChanged) {
|
||||
Context.setGlobal(global);
|
||||
Context.setGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user