8138882: Performance regression due to anonymous classloading
authorhannesw
Mon, 05 Oct 2015 18:58:21 +0200
changeset 32895 5a09b2d3d73a
parent 32894 4f60fd66fe73
child 32896 1d1ff2cf5846
8138882: Performance regression due to anonymous classloading Reviewed-by: attila, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties
nashorn/test/script/nosecurity/JDK-8044798.js
--- 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? " +