From d18e20a0fef71845ca1ec81125d241fd38563739 Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Mon, 2 Oct 2017 12:58:34 +0200
Subject: [PATCH] Implemented caching of Source objects.

---
 .../com/oracle/truffle/r/runtime/RSource.java | 47 +++++++++++++++----
 1 file changed, 39 insertions(+), 8 deletions(-)

diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
index 5ab18442c0..e913c165d5 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
@@ -24,13 +24,16 @@ package com.oracle.truffle.r.runtime;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.WeakHashMap;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.runtime.RSrcref.SrcrefFields;
@@ -94,6 +97,12 @@ public class RSource {
         }
     }
 
+    /**
+     * A weak map associating {@link Source} objects to corresponding origin (= {@link File} or
+     * {@link URL}, ...).
+     */
+    private static final WeakHashMap<Object, WeakReference<Source>> deserializedSources = new WeakHashMap<>();
+
     /**
      * Create an (external) source from the {@code text} that is known to originate from the file
      * system path {@code path}. The simulates the behavior of {@link #fromFile}.
@@ -166,32 +175,35 @@ public class RSource {
      * Create an (external) source from the file system path {@code path}.
      */
     public static Source fromFileName(String path, boolean internal) throws IOException {
-        Source.Builder<IOException, RuntimeException, RuntimeException> builder = Source.newBuilder(new File(path)).mimeType(RRuntime.R_APP_MIME);
-        if (internal) {
-            builder.internal();
-        }
-        return builder.build();
+        File file = new File(path);
+        return getCachedByOrigin(file, origin -> {
+            Source.Builder<IOException, RuntimeException, RuntimeException> builder = Source.newBuilder(new File(path)).mimeType(RRuntime.R_APP_MIME);
+            if (internal) {
+                builder.internal();
+            }
+            return builder.build();
+        });
     }
 
     /**
      * Create an (external) source from the file system path denoted by {@code file}.
      */
     public static Source fromFile(File file) throws IOException {
-        return Source.newBuilder(file).name(file.getName()).mimeType(RRuntime.R_APP_MIME).build();
+        return getCachedByOrigin(file, origin -> Source.newBuilder(file).name(file.getName()).mimeType(RRuntime.R_APP_MIME).build());
     }
 
     /**
      * Create a source from the file system path denoted by {@code file}.
      */
     public static Source fromTempFile(File file) throws IOException {
-        return Source.newBuilder(file).name(file.getName()).mimeType(RRuntime.R_APP_MIME).internal().build();
+        return getCachedByOrigin(file, origin -> Source.newBuilder(file).name(file.getName()).mimeType(RRuntime.R_APP_MIME).internal().build());
     }
 
     /**
      * Create an (external) source from {@code url}.
      */
     public static Source fromURL(URL url, String name) throws IOException {
-        return Source.newBuilder(url).name(name).mimeType(RRuntime.R_APP_MIME).build();
+        return getCachedByOrigin(url, origin -> Source.newBuilder(url).name(name).mimeType(RRuntime.R_APP_MIME).build());
     }
 
     /**
@@ -281,4 +293,23 @@ public class RSource {
             return path;
         }
     }
+
+    private static <T> Source getCachedByOrigin(T origin, SourceGenerator<T> generator) throws IOException {
+        CompilerAsserts.neverPartOfCompilation();
+        Source src;
+        synchronized (deserializedSources) {
+            WeakReference<Source> weakReference = deserializedSources.get(origin);
+            src = weakReference != null ? weakReference.get() : null;
+            if (src == null) {
+                src = generator.apply(origin);
+                deserializedSources.put(origin, new WeakReference<>(src));
+            }
+        }
+        return src;
+    }
+
+    @FunctionalInterface
+    private interface SourceGenerator<T> {
+        Source apply(T origin) throws IOException;
+    }
 }
-- 
GitLab