Thu, 02 Oct 2014 16:30:49 +0200
8059346: Single class loader is used to load compiled bytecode
Reviewed-by: hannesw, lagergren
1.1 --- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java Mon Sep 29 14:39:58 2014 -0700 1.2 +++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java Thu Oct 02 16:30:49 2014 +0200 1.3 @@ -100,4 +100,21 @@ 1.4 * @return compiled script data 1.5 */ 1.6 public StoredScript loadScript(Source source, String functionKey); 1.7 + 1.8 + /** 1.9 + * Returns a new code installer that shares most of the functionality of this code installer, but uses a 1.10 + * new, independent class loader. 1.11 + * @return a new code installer with a new independent class loader. 1.12 + */ 1.13 + public CodeInstaller<T> withNewLoader(); 1.14 + 1.15 + /** 1.16 + * Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be 1.17 + * an equivalence relation, and installers are supposed to be compatible with those they create using 1.18 + * {@link #withNewLoader()}. 1.19 + * @param other the other code installer tested for compatibility with this code installer. 1.20 + * @return true if this code installer is compatible with the other code installer. 1.21 + */ 1.22 + public boolean isCompatibleWith(CodeInstaller<T> other); 1.23 + 1.24 }
2.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Mon Sep 29 14:39:58 2014 -0700 2.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Thu Oct 02 16:30:49 2014 +0200 2.3 @@ -33,6 +33,7 @@ 2.4 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 2.5 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 2.6 import static jdk.nashorn.internal.runtime.Source.sourceFor; 2.7 + 2.8 import java.io.File; 2.9 import java.io.IOException; 2.10 import java.io.PrintWriter; 2.11 @@ -158,7 +159,7 @@ 2.12 } 2.13 2.14 /** 2.15 - * Return the context for this installer 2.16 + * Return the script environment for this installer 2.17 * @return ScriptEnvironment 2.18 */ 2.19 @Override 2.20 @@ -222,6 +223,20 @@ 2.21 } 2.22 return null; 2.23 } 2.24 + 2.25 + @Override 2.26 + public CodeInstaller<ScriptEnvironment> withNewLoader() { 2.27 + return new ContextCodeInstaller(context, context.createNewLoader(), codeSource); 2.28 + } 2.29 + 2.30 + @Override 2.31 + public boolean isCompatibleWith(final CodeInstaller<ScriptEnvironment> other) { 2.32 + if (other instanceof ContextCodeInstaller) { 2.33 + final ContextCodeInstaller cci = (ContextCodeInstaller)other; 2.34 + return cci.context == context && cci.codeSource == codeSource; 2.35 + } 2.36 + return false; 2.37 + } 2.38 } 2.39 2.40 /** Is Context global debug mode enabled ? */
3.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Mon Sep 29 14:39:58 2014 -0700 3.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Oct 02 16:30:49 2014 +0200 3.3 @@ -26,6 +26,7 @@ 3.4 package jdk.nashorn.internal.runtime; 3.5 3.6 import static jdk.nashorn.internal.lookup.Lookup.MH; 3.7 + 3.8 import java.io.IOException; 3.9 import java.lang.invoke.MethodHandle; 3.10 import java.lang.invoke.MethodHandles; 3.11 @@ -268,7 +269,7 @@ 3.12 if (this.source == null && this.installer == null) { 3.13 this.source = src; 3.14 this.installer = inst; 3.15 - } else if (this.source != src || this.installer != inst) { 3.16 + } else if (this.source != src || !this.installer.isCompatibleWith(inst)) { 3.17 // Existing values must be same as those passed as parameters 3.18 throw new IllegalArgumentException(); 3.19 } 3.20 @@ -407,6 +408,17 @@ 3.21 return getCompiler(fn, actualCallSiteType, newLocals(runtimeScope), null, null); 3.22 } 3.23 3.24 + /** 3.25 + * Returns a code installer for installing new code. If we're using either optimistic typing or loader-per-compile, 3.26 + * then asks for a code installer with a new class loader; otherwise just uses the current installer. We use 3.27 + * a new class loader with optimistic typing so that deoptimized code can get reclaimed by GC. 3.28 + * @return a code installer for installing new code. 3.29 + */ 3.30 + private CodeInstaller<ScriptEnvironment> getInstallerForNewCode() { 3.31 + final ScriptEnvironment env = installer.getOwner(); 3.32 + return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer; 3.33 + } 3.34 + 3.35 Compiler getCompiler(final FunctionNode functionNode, final MethodType actualCallSiteType, 3.36 final ScriptObject runtimeScope, final Map<Integer, Type> invalidatedProgramPoints, 3.37 final int[] continuationEntryPoints) { 3.38 @@ -417,7 +429,7 @@ 3.39 return new Compiler( 3.40 context, 3.41 context.getEnv(), 3.42 - installer, 3.43 + getInstallerForNewCode(), 3.44 functionNode.getSource(), // source 3.45 context.getErrorManager(), 3.46 isStrict() | functionNode.isStrict(), // is strict 3.47 @@ -463,11 +475,12 @@ 3.48 final TypeMap typeMap = typeMap(actualCallSiteType); 3.49 final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId); 3.50 cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes); 3.51 - final StoredScript script = installer.loadScript(source, cacheKey); 3.52 + final CodeInstaller<ScriptEnvironment> newInstaller = getInstallerForNewCode(); 3.53 + final StoredScript script = newInstaller.loadScript(source, cacheKey); 3.54 3.55 if (script != null) { 3.56 Compiler.updateCompilationId(script.getCompilationId()); 3.57 - return install(script); 3.58 + return installStoredScript(script, newInstaller); 3.59 } 3.60 } 3.61 3.62 @@ -481,15 +494,7 @@ 3.63 return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints()); 3.64 } 3.65 3.66 - 3.67 - /** 3.68 - * Install this script using the given {@code installer}. 3.69 - * 3.70 - * @param script the compiled script 3.71 - * @return the function initializer 3.72 - */ 3.73 - private FunctionInitializer install(final StoredScript script) { 3.74 - 3.75 + private static Map<String, Class<?>> installStoredScriptClasses(final StoredScript script, final CodeInstaller<ScriptEnvironment> installer) { 3.76 final Map<String, Class<?>> installedClasses = new HashMap<>(); 3.77 final Map<String, byte[]> classBytes = script.getClassBytes(); 3.78 final String mainClassName = script.getMainClassName(); 3.79 @@ -509,6 +514,17 @@ 3.80 3.81 installedClasses.put(className, installer.install(className, bytecode)); 3.82 } 3.83 + return installedClasses; 3.84 + } 3.85 + 3.86 + /** 3.87 + * Install this script using the given {@code installer}. 3.88 + * 3.89 + * @param script the compiled script 3.90 + * @return the function initializer 3.91 + */ 3.92 + private FunctionInitializer installStoredScript(final StoredScript script, final CodeInstaller<ScriptEnvironment> newInstaller) { 3.93 + final Map<String, Class<?>> installedClasses = installStoredScriptClasses(script, newInstaller); 3.94 3.95 final Map<Integer, FunctionInitializer> initializers = script.getInitializers(); 3.96 assert initializers != null; 3.97 @@ -523,7 +539,7 @@ 3.98 } 3.99 } 3.100 3.101 - installer.initialize(installedClasses.values(), source, constants); 3.102 + newInstaller.initialize(installedClasses.values(), source, constants); 3.103 initializer.setCode(installedClasses.get(initializer.getClassName())); 3.104 return initializer; 3.105 }