8138882: Performance regression due to anonymous classloading
Reviewed-by: attila, sundar
This commit is contained in:
parent
c1fa6e31e8
commit
26fc600426
@ -140,7 +140,7 @@ public final class Context {
|
||||
|
||||
private static final LongAdder NAMED_INSTALLED_SCRIPT_COUNT = new LongAdder();
|
||||
private static final LongAdder ANONYMOUS_INSTALLED_SCRIPT_COUNT = new LongAdder();
|
||||
private static final boolean DISABLE_VM_ANONYMOUS_CLASSES = Options.getBooleanProperty("nashorn.disableVmAnonymousClasses");
|
||||
|
||||
/**
|
||||
* Should scripts use only object slots for fields, or dual long/object slots? The default
|
||||
* behaviour is to couple this to optimistic types, using dual representation if optimistic types are enabled
|
||||
@ -775,7 +775,7 @@ public final class Context {
|
||||
* @return reusable compiled script across many global scopes.
|
||||
*/
|
||||
public MultiGlobalCompiledScript compileScript(final Source source) {
|
||||
final Class<?> clazz = compile(source, this.errors, this._strict);
|
||||
final Class<?> clazz = compile(source, this.errors, this._strict, false);
|
||||
final MethodHandle createProgramFunctionHandle = getCreateProgramFunctionHandle(clazz);
|
||||
|
||||
return new MultiGlobalCompiledScript() {
|
||||
@ -829,7 +829,7 @@ public final class Context {
|
||||
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = compile(source, new ThrowErrorManager(), strictFlag);
|
||||
clazz = compile(source, new ThrowErrorManager(), strictFlag, true);
|
||||
} catch (final ParserException e) {
|
||||
e.throwAsEcmaException(global);
|
||||
return null;
|
||||
@ -1379,10 +1379,10 @@ public final class Context {
|
||||
}
|
||||
|
||||
private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
|
||||
return getProgramFunction(compile(source, errMan, this._strict), scope);
|
||||
return getProgramFunction(compile(source, errMan, this._strict, false), scope);
|
||||
}
|
||||
|
||||
private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
|
||||
private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict, final boolean isEval) {
|
||||
// start with no errors, no warnings.
|
||||
errMan.reset();
|
||||
|
||||
@ -1434,7 +1434,7 @@ public final class Context {
|
||||
final URL url = source.getURL();
|
||||
final CodeSource cs = new CodeSource(url, (CodeSigner[])null);
|
||||
final CodeInstaller installer;
|
||||
if (DISABLE_VM_ANONYMOUS_CLASSES || env._persistent_cache || !env._lazy_compilation) {
|
||||
if (!env.useAnonymousClasses(isEval) || env._persistent_cache || !env._lazy_compilation) {
|
||||
// Persistent code cache and eager compilation preclude use of VM anonymous classes
|
||||
final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
|
||||
installer = new NamedContextCodeInstaller(this, cs, loader);
|
||||
|
@ -213,6 +213,14 @@ public final class ScriptEnvironment {
|
||||
/** Timing */
|
||||
public final Timing _timing;
|
||||
|
||||
/** Whether to use anonymous classes. See {@link #useAnonymousClasses(boolean)}. */
|
||||
private final AnonymousClasses _anonymousClasses;
|
||||
private enum AnonymousClasses {
|
||||
AUTO,
|
||||
OFF,
|
||||
ON
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -279,6 +287,18 @@ public final class ScriptEnvironment {
|
||||
_version = options.getBoolean("version");
|
||||
_verify_code = options.getBoolean("verify.code");
|
||||
|
||||
final String anonClasses = options.getString("anonymous.classes");
|
||||
if (anonClasses == null || anonClasses.equals("auto")) {
|
||||
_anonymousClasses = AnonymousClasses.AUTO;
|
||||
} else if (anonClasses.equals("true")) {
|
||||
_anonymousClasses = AnonymousClasses.ON;
|
||||
} else if (anonClasses.equals("false")) {
|
||||
_anonymousClasses = AnonymousClasses.OFF;
|
||||
} else {
|
||||
throw new RuntimeException("Unsupported value for anonymous classes: " + anonClasses);
|
||||
}
|
||||
|
||||
|
||||
final String language = options.getString("language");
|
||||
if (language == null || language.equals("es5")) {
|
||||
_es6 = false;
|
||||
@ -411,4 +431,13 @@ public final class ScriptEnvironment {
|
||||
return _timing != null ? _timing.isEnabled() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if compilation should use anonymous classes.
|
||||
* @param isEval true if compilation is an eval call.
|
||||
* @return true if anonymous classes should be used
|
||||
*/
|
||||
public boolean useAnonymousClasses(final boolean isEval) {
|
||||
return _anonymousClasses == AnonymousClasses.ON || (_anonymousClasses == AnonymousClasses.AUTO && isEval);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -380,6 +380,15 @@ nashorn.option.trace.callsites = {
|
||||
enterexit [trace callsite enter/exit], objects [print object properties]." \
|
||||
}
|
||||
|
||||
nashorn.option.anonymous.classes = { \
|
||||
name="--anonymous-classes", \
|
||||
is_undocumented=true, \
|
||||
params=[auto|true|false], \
|
||||
default=auto, \
|
||||
type=string, \
|
||||
desc="Use VM anonymous classes for compiled scripts." \
|
||||
}
|
||||
|
||||
nashorn.option.verify.code = { \
|
||||
name="--verify-code", \
|
||||
is_undocumented=true, \
|
||||
|
@ -126,12 +126,12 @@ var booleanCls = Java.type("java.lang.Boolean").TYPE;
|
||||
|
||||
// private compile method of Context class
|
||||
var compileMethod = Context.class.getDeclaredMethod("compile",
|
||||
sourceCls, errorMgrCls, booleanCls);
|
||||
sourceCls, errorMgrCls, booleanCls, booleanCls);
|
||||
compileMethod.accessible = true;
|
||||
|
||||
var scriptCls = compileMethod.invoke(Context.context,
|
||||
Source.sourceFor("test", "print('hello')"),
|
||||
new Context.ThrowErrorManager(), false);
|
||||
new Context.ThrowErrorManager(), false, false);
|
||||
|
||||
var SCRIPT_CLASS_NAME_PREFIX = "jdk.nashorn.internal.scripts.Script$";
|
||||
print("script class name pattern satisfied? " +
|
||||
|
Loading…
Reference in New Issue
Block a user