diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
index 64e03cca267097f2d160f8641fdf7d38d9fc6e5c..df12992a42bcc379d0c08517ec54dc2539d059fa 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
@@ -183,9 +183,8 @@ public class RCommand {
 
     public static ConsoleHandler createConsoleHandler(RCmdOptions options, DelegatingConsoleHandler useDelegatingWrapper, InputStream inStream, OutputStream outStream) {
         /*
-         * Whether the input is from stdin, a file (-f), or an expression on the command line (-e)
-         * it goes through the console. N.B. -f and -e can't be used together and this is already
-         * checked.
+         * Whether the input is from stdin, a file (-f), or an expression on the command line (-e) it goes
+         * through the console. N.B. -f and -e can't be used together and this is already checked.
          */
         RStartParams rsp = new RStartParams(options, false);
         String fileArgument = rsp.getFileArgument();
@@ -193,8 +192,8 @@ public class RCommand {
             List<String> lines;
             try {
                 /*
-                 * If initial==false, ~ expansion will not have been done and the open will fail.
-                 * It's harmless to always do it.
+                 * If initial==false, ~ expansion will not have been done and the open will fail. It's harmless to
+                 * always do it.
                  */
                 File file = fileArgument.startsWith("~") ? new File(System.getProperty("user.home") + fileArgument.substring(1)) : new File(fileArgument);
                 lines = Files.readAllLines(file.toPath());
@@ -216,9 +215,8 @@ public class RCommand {
             boolean useReadLine = isInteractive && !rsp.noReadline();
             if (useDelegatingWrapper != null) {
                 /*
-                 * If we are in embedded mode, the creation of ConsoleReader and the ConsoleHandler
-                 * should be lazy, as these may not be necessary and can cause hangs if stdin has
-                 * been redirected.
+                 * If we are in embedded mode, the creation of ConsoleReader and the ConsoleHandler should be lazy,
+                 * as these may not be necessary and can cause hangs if stdin has been redirected.
                  */
                 Supplier<ConsoleHandler> delegateFactory = useReadLine ? () -> new JLineConsoleHandler(inStream, outStream, rsp.isSlave())
                                 : () -> new DefaultConsoleHandler(inStream, outStream, isInteractive);
@@ -251,14 +249,14 @@ public class RCommand {
     }
 
     /**
-     * The read-eval-print loop, which can take input from a console, command line expression or a
-     * file. There are two ways the repl can terminate:
+     * The read-eval-print loop, which can take input from a console, command line expression or a file.
+     * There are two ways the repl can terminate:
      * <ol>
      * <li>A {@code quit} command is executed successfully.</li>
      * <li>EOF on the input.</li>
      * </ol>
-     * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before
-     * exiting. So,in either case, we never return.
+     * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before exiting.
+     * So,in either case, we never return.
      */
     public static int readEvalPrint(Context context, ConsoleHandler consoleHandler, File srcFile) {
         int lastStatus = 0;
@@ -286,7 +284,7 @@ public class RCommand {
                             Source src;
                             if (srcFile != null) {
                                 int endLine = consoleHandler.getCurrentLineIndex();
-                                src = Source.newBuilder("R", sb.toString(), srcFile.getName() + "#" + startLine + "-" + endLine).interactive(true).uri(srcFile.toURI()).buildLiteral();
+                                src = Source.newBuilder("R", sb.toString(), srcFile.toString() + "#" + startLine + "-" + endLine).interactive(true).uri(srcFile.toURI()).buildLiteral();
                             } else {
                                 src = Source.newBuilder("R", sb.toString(), "<REPL>").interactive(true).buildLiteral();
                             }
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java
index df41e3d0d2c420bb88c6699133eb5e1dc2f0417c..f92d3697ba5833dfbe6f37da88c4e8f578bb0a56 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@ import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.r.runtime.RParserFactory;
 import com.oracle.truffle.r.runtime.context.Engine.IncompleteSourceException;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.TruffleRLanguage;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 
@@ -45,7 +46,8 @@ public class DefaultRParserFactory extends RParserFactory {
         public List<T> script(Source source, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException {
             try {
                 try {
-                    RParser<T> parser = new RParser<>(source, builder, language);
+                    RContext context = language.getContextReference().get();
+                    RParser<T> parser = new RParser<>(source, builder, language, context.sourceCache);
                     return parser.script();
                 } catch (IllegalArgumentException e) {
                     // the lexer will wrap exceptions in IllegalArgumentExceptions
@@ -62,7 +64,8 @@ public class DefaultRParserFactory extends RParserFactory {
 
         @Override
         public RootCallTarget rootFunction(Source source, String name, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException {
-            RParser<T> parser = new RParser<>(source, builder, language);
+            RContext context = language.getContextReference().get();
+            RParser<T> parser = new RParser<>(source, builder, language, context.sourceCache);
             try {
                 return parser.root_function(name);
             } catch (RecognitionException e) {
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
index 21326517ababa0af8da39f71ae6c33dadeac4c8d..a86d1728d7e0fd16b916f60228ab2a974b939586 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
@@ -26,14 +26,15 @@ options {
 //@formatter:off
 package com.oracle.truffle.r.parser;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.io.File;
 import java.io.IOException;
+import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.frame.MaterializedFrame;
@@ -73,16 +74,18 @@ import com.oracle.truffle.r.runtime.RError;
     private RCodeBuilder<T> builder;
     private TruffleRLanguage language;
     private int fileStartOffset = 0;
+    private Map<String, Source> sourceCache;
     
     /**
      * Always use this constructor to initialize the R specific fields.
      */
-    public RParser(Source source, RCodeBuilder<T> builder, TruffleRLanguage language) {
+    public RParser(Source source, RCodeBuilder<T> builder, TruffleRLanguage language, Map<String, Source> sourceCache) {
         super(new CommonTokenStream(new RLexer(new ANTLRStringStream(source.getCharacters().toString()))));
         assert source != null && builder != null;
         this.initialSource = source;
         this.builder = builder;
         this.language = language;
+        this.sourceCache = sourceCache;
         if (source.getURI() != null && source.getName().contains("#")) {
         	this.source = createFullSource(source);
         } else {
@@ -91,53 +94,75 @@ import com.oracle.truffle.r.runtime.RError;
     }
     
     private Source createFullSource(Source original) {
-            String originalName = original.getName();
-
-            // check if source name is like 'path/to/source.R#45-54'
-            int hash_idx = originalName.lastIndexOf("#");
-            if (hash_idx == -1) {
-                return original;
-            }
+	    String originalName = original.getName();
 
-            String fileName = originalName.substring(0, hash_idx);
-            String lineRange = originalName.substring(hash_idx + 1);
-
-            try {
-                // check for line range, e.g. '45-54'
-                int startLine = -1;
-                int endLine = -1;
-                int dashIdx = lineRange.indexOf('-');
-                if (dashIdx != -1) {
-                    startLine = Integer.parseInt(lineRange.substring(0, dashIdx));
-                    endLine = Integer.parseInt(lineRange.substring(dashIdx + 1));
-                } else {
-                    startLine = Integer.parseInt(lineRange);
-                    endLine = startLine;
-                }
-                Builder<IOException, RuntimeException, RuntimeException> newBuilder = Source.newBuilder(new File(fileName));
-                if (original.isInteractive()) {
-                    newBuilder.interactive();
-                }
-                Source fullSource = newBuilder.build();
-
-                // verify to avoid accidentally matching file names
-                for (int i = 0; i < endLine - startLine + 1; i++) {
-                    if (!original.getCharacters(i + 1).equals(fullSource.getCharacters(startLine + i))) {
-                        return original;
-                    }
-                }
+	    // check if source name is like 'path/to/source.R#45-54'
+	    int hash_idx = originalName.lastIndexOf("#");
+	    if (hash_idx == -1) {
+	        return original;
+	    }
 
-                fileStartOffset = -fullSource.getLineStartOffset(startLine);
-                return fullSource;
-            } catch (NumberFormatException e) {
-            	// invalid line number
-            } catch (IllegalArgumentException e) {
-            	// file name is accidentally named in the expected scheme
-            } catch (IOException e) {
-            } catch (RuntimeException e) {
+	    String fileName = originalName.substring(0, hash_idx);
+	    String lineRange = originalName.substring(hash_idx + 1);
+
+	    try {
+	        // check for line range, e.g. '45-54'
+	        int startLine = -1;
+	        int endLine = -1;
+	        int dashIdx = lineRange.indexOf('-');
+	        if (dashIdx != -1) {
+	            startLine = Integer.parseInt(lineRange.substring(0, dashIdx));
+	            endLine = Integer.parseInt(lineRange.substring(dashIdx + 1));
+	        } else {
+	            startLine = Integer.parseInt(lineRange);
+	            endLine = startLine;
+	        }
+	        File f = new File(fileName);
+	        Source fullSource;
+	        String canonicalName;
+	        try {
+	            canonicalName = f.getAbsoluteFile().getCanonicalPath();
+	            fullSource = sourceCache != null ? sourceCache.get(canonicalName) : null;
+	        } catch(IOException e) {
+	            // ignore an freshly load file
+	            fullSource = null;
+	            canonicalName = null;
+	        }
+            if(fullSource == null) {
+    	        Builder<IOException, RuntimeException, RuntimeException> newBuilder = Source.newBuilder(f);
+    	        if (original.isInteractive()) {
+    	            newBuilder.interactive();
+    	        }
+    	        fullSource = newBuilder.build();
+    	        
+    	        if (sourceCache != null && canonicalName != null) {
+    	        	sourceCache.put(canonicalName, fullSource);
+    	        }
             }
-            return original;
-        }
+
+	        // verify to avoid accidentally matching file names
+	        for (int i = 0; i < endLine - startLine + 1; i++) {
+	            if (!original.getCharacters(i + 1).equals(fullSource.getCharacters(startLine + i))) {
+	                return original;
+	            }
+	        }
+
+	        fileStartOffset = -fullSource.getLineStartOffset(startLine);
+	        return fullSource;
+	    } catch (NumberFormatException e) {
+	        // invalid line number
+	    } catch (IllegalArgumentException e) {
+            // file name is accidentally named in the expected scheme
+	    } catch (IOException e) {
+	    } catch (RuntimeException e) {
+	    	assert rethrow(e);
+	    }
+	    return original;
+	}
+        
+    private <T extends Throwable> boolean rethrow(T e) throws T {
+    	throw e;
+    }
     
     /**
      * Helper function that returns the last parsed token, usually used for building source sections.
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index 393a3df3fddce03701f21938395fb5cf51231754..14cbbbc8216169c4ca2e8770410c69787fec6a70 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -361,6 +361,7 @@ public final class RContext {
     public final List<String> libraryPaths = new ArrayList<>(1);
     public final Map<Integer, Thread> threads = new ConcurrentHashMap<>();
     public final LanguageClosureCache languageClosureCache = new LanguageClosureCache();
+    public final Map<String, Source> sourceCache = new ConcurrentHashMap<>();
 
     private final AllocationReporter allocationReporter;