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); + } + } + + }