8059346: Single class loader is used to load compiled bytecode

Reviewed-by: hannesw, lagergren
This commit is contained in:
Attila Szegedi 2014-10-02 16:30:49 +02:00
parent e97393b108
commit c7df19bca4
3 changed files with 63 additions and 15 deletions
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime

@ -100,4 +100,21 @@ public interface CodeInstaller<T> {
* @return compiled script data
*/
public StoredScript loadScript(Source source, String functionKey);
/**
* Returns a new code installer that shares most of the functionality of this code installer, but uses a
* new, independent class loader.
* @return a new code installer with a new independent class loader.
*/
public CodeInstaller<T> withNewLoader();
/**
* Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be
* an equivalence relation, and installers are supposed to be compatible with those they create using
* {@link #withNewLoader()}.
* @param other the other code installer tested for compatibility with this code installer.
* @return true if this code installer is compatible with the other code installer.
*/
public boolean isCompatibleWith(CodeInstaller<T> other);
}

@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
@ -158,7 +159,7 @@ public final class Context {
}
/**
* Return the context for this installer
* Return the script environment for this installer
* @return ScriptEnvironment
*/
@Override
@ -222,6 +223,20 @@ public final class Context {
}
return null;
}
@Override
public CodeInstaller<ScriptEnvironment> withNewLoader() {
return new ContextCodeInstaller(context, context.createNewLoader(), codeSource);
}
@Override
public boolean isCompatibleWith(final CodeInstaller<ScriptEnvironment> other) {
if (other instanceof ContextCodeInstaller) {
final ContextCodeInstaller cci = (ContextCodeInstaller)other;
return cci.context == context && cci.codeSource == codeSource;
}
return false;
}
}
/** Is Context global debug mode enabled ? */

@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@ -268,7 +269,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
if (this.source == null && this.installer == null) {
this.source = src;
this.installer = inst;
} else if (this.source != src || this.installer != inst) {
} else if (this.source != src || !this.installer.isCompatibleWith(inst)) {
// Existing values must be same as those passed as parameters
throw new IllegalArgumentException();
}
@ -407,6 +408,17 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return getCompiler(fn, actualCallSiteType, newLocals(runtimeScope), null, null);
}
/**
* Returns a code installer for installing new code. If we're using either optimistic typing or loader-per-compile,
* then asks for a code installer with a new class loader; otherwise just uses the current installer. We use
* a new class loader with optimistic typing so that deoptimized code can get reclaimed by GC.
* @return a code installer for installing new code.
*/
private CodeInstaller<ScriptEnvironment> getInstallerForNewCode() {
final ScriptEnvironment env = installer.getOwner();
return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer;
}
Compiler getCompiler(final FunctionNode functionNode, final MethodType actualCallSiteType,
final ScriptObject runtimeScope, final Map<Integer, Type> invalidatedProgramPoints,
final int[] continuationEntryPoints) {
@ -417,7 +429,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return new Compiler(
context,
context.getEnv(),
installer,
getInstallerForNewCode(),
functionNode.getSource(), // source
context.getErrorManager(),
isStrict() | functionNode.isStrict(), // is strict
@ -463,11 +475,12 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
final TypeMap typeMap = typeMap(actualCallSiteType);
final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes);
final StoredScript script = installer.loadScript(source, cacheKey);
final CodeInstaller<ScriptEnvironment> newInstaller = getInstallerForNewCode();
final StoredScript script = newInstaller.loadScript(source, cacheKey);
if (script != null) {
Compiler.updateCompilationId(script.getCompilationId());
return install(script);
return installStoredScript(script, newInstaller);
}
}
@ -481,15 +494,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints());
}
/**
* Install this script using the given {@code installer}.
*
* @param script the compiled script
* @return the function initializer
*/
private FunctionInitializer install(final StoredScript script) {
private static Map<String, Class<?>> installStoredScriptClasses(final StoredScript script, final CodeInstaller<ScriptEnvironment> installer) {
final Map<String, Class<?>> installedClasses = new HashMap<>();
final Map<String, byte[]> classBytes = script.getClassBytes();
final String mainClassName = script.getMainClassName();
@ -509,6 +514,17 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
installedClasses.put(className, installer.install(className, bytecode));
}
return installedClasses;
}
/**
* Install this script using the given {@code installer}.
*
* @param script the compiled script
* @return the function initializer
*/
private FunctionInitializer installStoredScript(final StoredScript script, final CodeInstaller<ScriptEnvironment> newInstaller) {
final Map<String, Class<?>> installedClasses = installStoredScriptClasses(script, newInstaller);
final Map<Integer, FunctionInitializer> initializers = script.getInitializers();
assert initializers != null;
@ -523,7 +539,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
}
}
installer.initialize(installedClasses.values(), source, constants);
newInstaller.initialize(installedClasses.values(), source, constants);
initializer.setCode(installedClasses.get(initializer.getClassName()));
return initializer;
}