# HG changeset patch # User hannesw # Date 1444064301 -7200 # Node ID 5a09b2d3d73a20e90287df6915835363a8cc9ef0 # Parent 4f60fd66fe73fbc37b37cf7b88fe76654bfa968c 8138882: Performance regression due to anonymous classloading Reviewed-by: attila, sundar diff -r 4f60fd66fe73 -r 5a09b2d3d73a nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java --- 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); diff -r 4f60fd66fe73 -r 5a09b2d3d73a nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java --- 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); + } + } diff -r 4f60fd66fe73 -r 5a09b2d3d73a nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Options.properties --- 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, \ diff -r 4f60fd66fe73 -r 5a09b2d3d73a nashorn/test/script/nosecurity/JDK-8044798.js --- 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? " +