8138882: Performance regression due to anonymous classloading

Reviewed-by: attila, sundar
This commit is contained in:
Hannes Wallnöfer 2015-10-05 18:58:21 +02:00
parent c1fa6e31e8
commit 26fc600426
4 changed files with 46 additions and 8 deletions

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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, \

View File

@ -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? " +