src/jdk/nashorn/internal/runtime/Context.java

Print this page

        

@@ -149,20 +149,28 @@
 
         @Override
         public long getUniqueEvalId() {
             return context.getUniqueEvalId();
         }
+
+        @Override
+        public CodeCache getCodeCache() {
+            return context.codeCache;
+        }
     }
 
     /** Is Context global debug mode enabled ? */
     public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
 
     private static final ThreadLocal<Global> currentGlobal = new ThreadLocal<>();
 
-    // class cache
+    // cache for loaded classes
     private ClassCache classCache;
 
+    // persistent code cache
+    private CodeCache codeCache;
+
     /**
      * Get the current global scope
      * @return the current global scope
      */
     public static Global getGlobal() {

@@ -366,10 +374,23 @@
         final int cacheSize = env._class_cache_size;
         if (cacheSize > 0) {
             classCache = new ClassCache(cacheSize);
         }
 
+        if (env._persistent_cache) {
+            if (env._lazy_compilation || env._specialize_calls != null) {
+                getErr().println("Can not use persistent class caching with lazy compilation or call specialization.");
+            } else {
+                try {
+                    final String cacheDir = Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache");
+                    codeCache = new PersistentCodeCache(cacheDir);
+                } catch (IOException e) {
+                    throw new RuntimeException("Error initializing code cache", e);
+                }
+            }
+        }
+
         // print version info if asked.
         if (env._version) {
             getErr().println("nashorn " + Version.version());
         }
 

@@ -930,11 +951,25 @@
         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();
+        PersistentCodeCache.CachedScript cachedScript = null;
+        FunctionNode functionNode = null;
+
+        if (!env._parse_only && codeCache != null) {
+            try {
+                cachedScript = codeCache.getScript(source);
+            } catch (IOException | ClassNotFoundException e) {
+                Compiler.LOG.warning("Error loading ", source, " from cache: ", e);
+                // Fall back to normal compilation
+            }
+        }
+
+        if (cachedScript == null) {
+            functionNode = new Parser(env, source, errMan, strict).parse();
+
         if (errors.hasErrors()) {
             return null;
         }
 
         if (env._print_ast) {

@@ -942,10 +977,11 @@
         }
 
         if (env._print_parse) {
             getErr().println(new PrintVisitor(functionNode));
         }
+        }
 
         if (env._parse_only) {
             return null;
         }
 

@@ -954,14 +990,18 @@
         final CodeSource   cs     = new CodeSource(url, (CodeSigner[])null);
         final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
 
         final Compiler compiler = new Compiler(installer, strict);
 
+        if (functionNode != null) {
         final FunctionNode newFunctionNode = compiler.compile(functionNode);
         script = compiler.install(newFunctionNode);
-        cacheClass(source, script);
+        } else {
+            script = compiler.install(cachedScript);
+        }
 
+        cacheClass(source, script);
         return script;
     }
 
     private ScriptLoader createNewLoader() {
         return AccessController.doPrivileged(