8138882: Performance regression due to anonymous classloading
Reviewed-by: attila, sundar
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Fri Oct 02 15:50:49 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Mon Oct 05 18:58:21 2015 +0200
@@ -140,7 +140,7 @@
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 @@
* @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 @@
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 @@
}
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 @@
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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri Oct 02 15:50:49 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Mon Oct 05 18:58:21 2015 +0200
@@ -213,6 +213,14 @@
/** 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 @@
_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 @@
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);
+ }
+
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties Fri Oct 02 15:50:49 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties Mon Oct 05 18:58:21 2015 +0200
@@ -380,6 +380,15 @@
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, \
--- a/nashorn/test/script/nosecurity/JDK-8044798.js Fri Oct 02 15:50:49 2015 +0200
+++ b/nashorn/test/script/nosecurity/JDK-8044798.js Mon Oct 05 18:58:21 2015 +0200
@@ -126,12 +126,12 @@
// 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? " +