diff --git a/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R b/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R
index e144580e27a84b4730638cc6f8cc3cece2e3e508..43f9187cebfade9b0f492e8cd0cc431297e65570 100644
--- a/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R
+++ b/com.oracle.truffle.r.native/library/fastr/src/R/fastr.R
@@ -71,7 +71,7 @@ fastr.createpkgsource <- function(pkg, name) {
 
 fastr.comparefilesizes <- function(file1, file2) .FastR(.NAME="comparefilesizes", file1, file2)
 
-fastr_context.create <- function(args, shared=FALSE) {
+fastr_context.create <- function(args="", shared=FALSE) {
 	context <- .FastR(.NAME="context.create", args, shared)
 	class(context) <- "fastr_context"
     context
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
index 78b65a786ad06b3b707e50554164e0bb8f54687f..ca6b7287811b2219c6a440a4e4aef3d84ab9d749 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
@@ -53,13 +53,31 @@ public class FastRContext {
         }
     }
 
-    static Object eval(int contextId, String expr) {
-        RContext context = checkContext(contextId);
-        try {
-            context.activate();
-            return context.getThisEngine().parseAndEval(Source.fromText(expr, "<eval_input>"), true, false);
-        } finally {
-            context.destroy();
+    static void eval(RIntVector contexts, RStringVector exprs) {
+        if (contexts.getLength() == 1) {
+            RContext context = checkContext(contexts.getDataAt(0));
+            try {
+                context.activate();
+                context.getThisEngine().parseAndEval(Source.fromText(exprs.getDataAt(0), "<eval_input>"), true, false);
+            } finally {
+                context.destroy();
+            }
+        } else {
+            RContext.EvalThread[] threads = new RContext.EvalThread[contexts.getLength()];
+            for (int i = 0; i < threads.length; i++) {
+                RContext context = checkContext(contexts.getDataAt(i));
+                threads[i] = new RContext.EvalThread(context, Source.fromText(exprs.getDataAt(i % threads.length), "context_eval"));
+            }
+            for (int i = 0; i < threads.length; i++) {
+                threads[i].start();
+            }
+            try {
+                for (int i = 0; i < threads.length; i++) {
+                    threads[i].join();
+                }
+            } catch (InterruptedException ex) {
+
+            }
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionEntry.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionEntry.java
index b35897c3bf140b699dc27147786bbbe18121f069..a432deedad7a94fbc6794b12d084cae0a20625b2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionEntry.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionEntry.java
@@ -73,7 +73,8 @@ public class FastRFunctionEntry {
                 return RNull.instance;
 
             case "context.eval":
-                return FastRContext.eval(((RIntVector) RRuntime.asAbstractVector(arg0)).getDataAt(0), ((RStringVector) RRuntime.asAbstractVector(argValues[1])).getDataAt(0));
+                FastRContext.eval((RIntVector) RRuntime.asAbstractVector(arg0), (RStringVector) RRuntime.asAbstractVector(argValues[1]));
+                return RNull.instance;
 
             default:
                 // The remainder all take a func argument
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java
index c5d974fe2cda2cda32fd96f152249fae6fcfc275..ed983a04a514a92e8599749c40d15c75298d99fd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RContext.java
@@ -360,6 +360,49 @@ public final class RContext extends ExecutionContext {
 
     }
 
+    /**
+     * A thread that is explicitly associated with a context for efficient lookup.
+     */
+    public static class ContextThread extends Thread {
+        protected RContext context;
+
+        public ContextThread(RContext context) {
+            this.context = context;
+        }
+
+        protected ContextThread() {
+
+        }
+
+        public void setContext(RContext context) {
+            this.context = context;
+        }
+
+    }
+
+    /**
+     * A thread for performing an evaluation (used by {@code fastr} package.
+     */
+    public static class EvalThread extends ContextThread {
+        private final Source source;
+
+        public EvalThread(RContext context, Source source) {
+            super(context);
+            this.source = source;
+        }
+
+        @Override
+        public void run() {
+            try {
+                context.activate();
+                context.engine.parseAndEval(source, true, false);
+            } finally {
+                context.destroy();
+            }
+        }
+
+    }
+
     /**
      * Builtin cache. Valid across all contexts.
      */
@@ -446,7 +489,12 @@ public final class RContext extends ExecutionContext {
      * Associates this {@link RContext} with the current thread.
      */
     public void attachThread() {
-        threadLocalContext.set(this);
+        Thread current = Thread.currentThread();
+        if (current instanceof ContextThread) {
+            ((ContextThread) current).setContext(this);
+        } else {
+            threadLocalContext.set(this);
+        }
     }
 
     private static final Assumption singleContextAssumption = Truffle.getRuntime().createAssumption("single RContext");
@@ -614,7 +662,16 @@ public final class RContext extends ExecutionContext {
                 // fallback to slow case
             }
         }
-        return getInstanceInternal();
+
+        Thread current = Thread.currentThread();
+        if (current instanceof ContextThread) {
+            context = ((ContextThread) current).context;
+            assert context != null;
+            return context;
+        } else {
+            return getInstanceInternal();
+        }
+
     }
 
     /**
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
index d69fd5a192e5ca9a9bd36e1a0c6f4281f3f95f66..7d821aac4e836a6745b33745be9e75e1f3ee301c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
@@ -147,7 +147,7 @@ public final class FastRSession implements RSession {
         return consoleHandler.buffer.toString();
     }
 
-    private final class EvalThread extends Thread {
+    private final class EvalThread extends RContext.ContextThread {
 
         private volatile String expression;
         private volatile Throwable killedByException;
@@ -172,11 +172,11 @@ public final class FastRSession implements RSession {
                     break;
                 }
                 try {
-                    RContext context = createTestContext();
+                    RContext testContext = createTestContext();
                     try {
-                        context.getThisEngine().parseAndEval(Source.fromText(expression, "<test_input>"), true, false);
+                        testContext.getThisEngine().parseAndEval(Source.fromText(expression, "<test_input>"), true, false);
                     } finally {
-                        context.destroy();
+                        testContext.destroy();
                     }
                 } catch (RError e) {
                     // nothing to do