src/jdk/nashorn/internal/runtime/Context.java
Print this page
*** 34,53 ****
--- 34,56 ----
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+ import java.lang.ref.ReferenceQueue;
+ import java.lang.ref.SoftReference;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
+ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
*** 153,162 ****
--- 156,168 ----
/** Is Context global debug mode enabled ? */
public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
private static final ThreadLocal<ScriptObject> currentGlobal = new ThreadLocal<>();
+ // class cache
+ private ClassCache classCache;
+
/**
* Get the current global scope
* @return the current global scope
*/
public static ScriptObject getGlobal() {
*** 346,355 ****
--- 352,366 ----
this.classPathLoader = NashornLoader.createClassLoader(classPath);
} else {
this.classPathLoader = null;
}
+ final int cacheSize = env._class_cache_size;
+ if (cacheSize > 0) {
+ classCache = new ClassCache(cacheSize);
+ }
+
// print version info if asked.
if (env._version) {
getErr().println("nashorn " + Version.version());
}
*** 657,667 ****
* @throw SecurityException if not accessible
*/
public static void checkPackageAccess(final String pkgName) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
! checkPackageAccess(sm, pkgName.endsWith(".")? pkgName : pkgName + ".");
}
}
/**
* Checks that the given package can be accessed from no permissions context.
--- 668,678 ----
* @throw SecurityException if not accessible
*/
public static void checkPackageAccess(final String pkgName) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
! checkPackageAccess(sm, pkgName.endsWith(".") ? pkgName : pkgName + ".");
}
}
/**
* Checks that the given package can be accessed from no permissions context.
*** 923,943 ****
private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
// start with no errors, no warnings.
errMan.reset();
! GlobalObject global = null;
! Class<?> script;
!
! if (env._class_cache_size > 0) {
! global = (GlobalObject)Context.getGlobalTrusted();
! script = global.findCachedClass(source);
if (script != null) {
Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
return script;
}
- }
final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
if (errors.hasErrors()) {
return null;
}
--- 934,948 ----
private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
// start with no errors, no warnings.
errMan.reset();
! Class<?> script = findCachedClass(source);
if (script != null) {
Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
return script;
}
final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
if (errors.hasErrors()) {
return null;
}
*** 961,974 ****
final Compiler compiler = new Compiler(installer, strict);
final FunctionNode newFunctionNode = compiler.compile(functionNode);
script = compiler.install(newFunctionNode);
!
! if (global != null) {
! global.cacheClass(source, script);
! }
return script;
}
private ScriptLoader createNewLoader() {
--- 966,976 ----
final Compiler compiler = new Compiler(installer, strict);
final FunctionNode newFunctionNode = compiler.compile(functionNode);
script = compiler.install(newFunctionNode);
! cacheClass(source, script);
return script;
}
private ScriptLoader createNewLoader() {
*** 986,991 ****
--- 988,1049 ----
}
private long getUniqueScriptId() {
return uniqueScriptId.getAndIncrement();
}
+
+ /**
+ * Cache for compiled script classes.
+ */
+ @SuppressWarnings("serial")
+ private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
+ private final int size;
+ private final ReferenceQueue<Class<?>> queue;
+
+ ClassCache(int size) {
+ super(size, 0.75f, true);
+ this.size = size;
+ this.queue = new ReferenceQueue<>();
+ }
+
+ void cache(final Source source, final Class<?> clazz) {
+ put(source, new ClassReference(clazz, queue, source));
+ }
+
+ @Override
+ protected boolean removeEldestEntry(final Map.Entry<Source, ClassReference> eldest) {
+ return size() > size;
+ }
+
+ @Override
+ public ClassReference get(Object key) {
+ for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
+ remove(ref.source);
+ }
+ return super.get(key);
+ }
+
+ }
+
+ private static class ClassReference extends SoftReference<Class<?>> {
+ private final Source source;
+
+ ClassReference(final Class<?> clazz, final ReferenceQueue<Class<?>> queue, final Source source) {
+ super(clazz, queue);
+ this.source = source;
+ }
+ }
+
+ // Class cache management
+ private Class<?> findCachedClass(final Source source) {
+ ClassReference ref = classCache == null ? null : classCache.get(source);
+ return ref != null ? ref.get() : null;
+ }
+
+ private void cacheClass(final Source source, final Class<?> clazz) {
+ if (classCache != null) {
+ classCache.cache(source, clazz);
+ }
+ }
+
+
}