From 743960e1aee61bb6808397f6a115b8236b6031d4 Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Tue, 19 May 2015 13:31:01 -0700
Subject: [PATCH] add ContextThread and used it in unit tests; implement
 parallel contexts

---
 .../library/fastr/src/R/fastr.R               |  2 +-
 .../r/nodes/builtin/fastr/FastRContext.java   | 32 +++++++---
 .../builtin/fastr/FastRFunctionEntry.java     |  3 +-
 .../oracle/truffle/r/runtime/RContext.java    | 61 ++++++++++++++++++-
 .../truffle/r/test/generate/FastRSession.java |  8 +--
 5 files changed, 91 insertions(+), 15 deletions(-)

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 e144580e27..43f9187ceb 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 78b65a786a..ca6b728781 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 b35897c3bf..a432deedad 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 c5d974fe2c..ed983a04a5 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 d69fd5a192..7d821aac4e 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
-- 
GitLab