From 1118567889cd6f635dec218ff05613d86b567d7e Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Wed, 26 Jul 2017 15:43:19 -0700
Subject: [PATCH] Changes for Truffle Polyglot rev 12

---
 .../com/oracle/truffle/r/engine/REngine.java  |  5 ++
 .../truffle/r/engine/shell/REmbedded.java     | 15 ++--
 .../oracle/truffle/r/launcher/Launcher.java   | 18 +----
 .../oracle/truffle/r/launcher/RCommand.java   |  8 +-
 .../r/nodes/builtin/fastr/FastRContext.java   | 41 ++++++----
 .../truffle/r/runtime/FastROptions.java       |  1 +
 ...ContextInfo.java => ChildContextInfo.java} | 42 ++++++++---
 .../truffle/r/runtime/context/Engine.java     |  6 ++
 .../truffle/r/runtime/context/EvalThread.java | 75 ++++++++++++++++---
 .../truffle/r/runtime/context/RContext.java   | 28 ++++---
 .../env/frame/FrameSlotChangeMonitor.java     |  6 +-
 .../com/oracle/truffle/r/test/TestBase.java   |  6 +-
 .../truffle/r/test/generate/FastRSession.java | 16 ++--
 .../r/test/generate/GnuROneShotRSession.java  |  4 +-
 .../truffle/r/test/generate/RSession.java     |  4 +-
 .../truffle/r/test/tck/FastRDebugTest.java    |  4 +-
 mx.fastr/suite.py                             |  2 +-
 17 files changed, 189 insertions(+), 92 deletions(-)
 rename com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/{ContextInfo.java => ChildContextInfo.java} (75%)

diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 80b3c4825c..50d3fb27c9 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -234,6 +234,11 @@ final class REngine implements Engine, Engine.Timings {
         return this;
     }
 
+    @Override
+    public MaterializedFrame getGlobalFrame() {
+        return globalFrame;
+    }
+
     @Override
     public long elapsedTimeInNanos() {
         return System.nanoTime() - startTime;
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java
index 39a0b3a60a..a05716cad3 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.launcher.RStartParams;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource.Internal;
 import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 import com.oracle.truffle.r.runtime.context.RContext;
 
 /**
@@ -54,12 +54,13 @@ import com.oracle.truffle.r.runtime.context.RContext;
  * </pre>
  *
  * {@code Rf_initialize_R} invokes {@link #initializeR(String[])}. This creates an
- * {@link RStartParams} object in {@code embedded} mode that is recorded in the {@link ContextInfo}
- * object which is itself stored as a global symbol in the associated {@link PolyglotEngine}
- * instance. The FastR {@link PolyglotEngine} is then partially initialized. The call to
- * {@code R_SetParams} will adjust the values stored in the {@link RStartParams} object and then
- * {@code Rf_mainloop}, which calls {@link #setupRmainloop()} and then {@link #runRmainloop()},
- * which will complete the FastR initialization and enter the read-eval-print loop.
+ * {@link RStartParams} object in {@code embedded} mode that is recorded in the
+ * {@link ChildContextInfo} object which is itself stored as a global symbol in the associated
+ * {@link PolyglotEngine} instance. The FastR {@link PolyglotEngine} is then partially initialized.
+ * The call to {@code R_SetParams} will adjust the values stored in the {@link RStartParams} object
+ * and then {@code Rf_mainloop}, which calls {@link #setupRmainloop()} and then
+ * {@link #runRmainloop()}, which will complete the FastR initialization and enter the
+ * read-eval-print loop.
  */
 public class REmbedded {
 
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/Launcher.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/Launcher.java
index c95b28a240..15052181a4 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/Launcher.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/Launcher.java
@@ -333,9 +333,9 @@ public abstract class Launcher {
             default:
                 Engine engine = getTempEngine();
                 if (engine.getLanguages().containsKey(group)) {
-                    descriptors = engine.getLanguage(group).getOptions();
+                    descriptors = engine.getLanguages().get(group).getOptions();
                 } else if (engine.getInstruments().containsKey(group)) {
-                    descriptors = engine.getInstrument(group).getOptions();
+                    descriptors = engine.getInstruments().get(group).getOptions();
                 }
                 break;
         }
@@ -460,30 +460,18 @@ public abstract class Launcher {
             System.out.println("  Installed Languages:");
             List<Language> languages = new ArrayList<>(engine.getLanguages().size());
             int nameLength = 0;
-            boolean hasHost = false;
             for (Language language : engine.getLanguages().values()) {
                 languages.add(language);
                 nameLength = max(nameLength, language.getName().length());
-                hasHost |= language.isHost();
             }
             languages.sort(Comparator.comparing(Language::getId));
             String langFormat = "    %-" + nameLength + "s%s version %s%n";
             for (Language language : languages) {
-                String host;
-                if (hasHost) {
-                    if (language.isHost()) {
-                        host = " (Host)";
-                    } else {
-                        host = "       ";
-                    }
-                } else {
-                    host = "";
-                }
                 String version = language.getVersion();
                 if (version == null || version.length() == 0) {
                     version = "";
                 }
-                System.out.printf(langFormat, language.getName().isEmpty() ? "Unnamed" : language.getName(), host, version);
+                System.out.printf(langFormat, language.getName().isEmpty() ? "Unnamed" : language.getName(), version);
             }
         }
     }
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 a173a08ec6..fc99b4772b 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
@@ -129,7 +129,11 @@ public class RCommand {
                 }
             }
             if (addArg) {
-                argsList.add(1, "--interactive");
+                if (argsList.size() == 0) {
+                    argsList.add("--interactive");
+                } else {
+                    argsList.add(1, "--interactive");
+                }
             }
         }
 
@@ -145,7 +149,7 @@ public class RCommand {
             return 0;
         }
         RCmdOptions options = RCmdOptions.parseArguments(Client.R, argsList.toArray(new String[argsList.size()]), false);
-        assert env == null : "re-enable setting environments";
+        assert env == null || env.length == 0 : "re-enable setting environments";
         ConsoleHandler consoleHandler = createConsoleHandler(options, false, inStream, outStream);
         try (Context context = Context.newBuilder().options(polyglotOptions).arguments("R", options.getArguments()).in(consoleHandler.createInputStream()).out(outStream).err(errStream).build()) {
             consoleHandler.setContext(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 930598b4ff..5fad15577e 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
@@ -34,6 +34,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleContext;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.TruffleObject;
@@ -48,7 +49,7 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 import com.oracle.truffle.r.runtime.context.EvalThread;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ConsoleIO;
@@ -100,7 +101,7 @@ public class FastRContext {
         if (contextKind == ContextKind.SHARE_ALL && EvalThread.threadCnt.get() == 0) {
             RContext current = RContext.getInstance();
             if (EvalThread.threadCnt.get() == 0 && (current.isInitial() || current.getKind() == ContextKind.SHARE_PARENT_RW)) {
-                ContextInfo.resetMultiSlotIndexGenerator();
+                ChildContextInfo.resetMultiSlotIndexGenerator();
             } else {
                 throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, "Shared contexts can be created only if no other child contexts exist");
             }
@@ -140,8 +141,12 @@ public class FastRContext {
             int[] data = new int[length];
             int[] multiSlotIndices = new int[length];
             for (int i = 0; i < length; i++) {
-                ContextInfo info = createContextInfo(contextKind);
-                threads[i] = new EvalThread(info, RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL));
+                ChildContextInfo info = createContextInfo(contextKind);
+                if (FastROptions.SpawnUsesPloyglot.getBooleanValue()) {
+                    threads[i] = new EvalThread(info, RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL), true);
+                } else {
+                    threads[i] = new EvalThread(info, RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL));
+                }
                 data[i] = info.getId();
                 multiSlotIndices[i] = info.getMultiSlotInd();
             }
@@ -234,19 +239,15 @@ public class FastRContext {
             int length = exprs.getLength();
             Object[] results = new Object[length];
             if (length == 1) {
-                ContextInfo info = createContextInfo(contextKind);
-                PolyglotEngine vm = info.createVM();
-                try {
-                    results[0] = EvalThread.run(vm, info, RSource.fromTextInternalInvisible(exprs.getDataAt(0), RSource.Internal.CONTEXT_EVAL));
-                } finally {
-                    vm.dispose();
-                }
+                ChildContextInfo info = createContextInfo(contextKind);
+                TruffleContext truffleContext = info.createTruffleContext();
+                results[0] = EvalThread.run(truffleContext, info, RSource.fromTextInternalInvisible(exprs.getDataAt(0), RSource.Internal.CONTEXT_EVAL));
             } else {
                 // separate threads that run in parallel; invoking thread waits for completion
                 EvalThread[] threads = new EvalThread[length];
                 int[] multiSlotIndices = new int[length];
                 for (int i = 0; i < length; i++) {
-                    ContextInfo info = createContextInfo(contextKind);
+                    ChildContextInfo info = createContextInfo(contextKind);
                     threads[i] = new EvalThread(info, RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL));
                     multiSlotIndices[i] = info.getMultiSlotInd();
                 }
@@ -291,7 +292,7 @@ public class FastRContext {
         @Specialization
         @TruffleBoundary
         protected Object r(RAbstractStringVector args, RAbstractStringVector env, boolean intern) {
-            Object rc = RContext.getRRuntimeASTAccess().rcommandMain(args.materialize().getDataCopy(), env.materialize().getDataCopy(), intern);
+            Object rc = RContext.getRRuntimeASTAccess().rcommandMain(prependCommand(args, "R"), env.materialize().getDataCopy(), intern);
             return rc;
         }
 
@@ -327,7 +328,7 @@ public class FastRContext {
         @Specialization
         @TruffleBoundary
         protected Object rscript(RAbstractStringVector args, RAbstractStringVector env, boolean intern) {
-            return RContext.getRRuntimeASTAccess().rscriptMain(args.materialize().getDataCopy(), env.materialize().getDataCopy(), intern);
+            return RContext.getRRuntimeASTAccess().rscriptMain(prependCommand(args, "Rscript"), env.materialize().getDataCopy(), intern);
         }
 
         @Specialization
@@ -337,10 +338,18 @@ public class FastRContext {
         }
     }
 
-    private static ContextInfo createContextInfo(RContext.ContextKind contextKind) {
+    private static String[] prependCommand(RAbstractStringVector argsVec, String command) {
+        String[] argsVecArgs = argsVec.materialize().getDataCopy();
+        String[] result = new String[argsVecArgs.length + 1];
+        result[0] = command;
+        System.arraycopy(argsVecArgs, 0, result, 1, argsVecArgs.length);
+        return result;
+    }
+
+    private static ChildContextInfo createContextInfo(RContext.ContextKind contextKind) {
         RContext context = RContext.getInstance();
         ConsoleIO console = context.getConsole();
-        return ContextInfo.createNoRestore(Client.RSCRIPT, null, contextKind, context, console.getStdin(), console.getStdout(), console.getStderr());
+        return ChildContextInfo.createNoRestore(Client.RSCRIPT, null, contextKind, context, console.getStdin(), console.getStdout(), console.getStderr());
     }
 
     @RBuiltin(name = ".fastr.channel.create", kind = PRIMITIVE, parameterNames = {"key"}, behavior = COMPLEX)
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
index a3bac44785..935d7b6995 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
@@ -60,6 +60,7 @@ public enum FastROptions {
     EmitTmpSource("Write deparsed source code to temporary files for better debugging.", true),
     EmitTmpDir("The directory where to allocate temporary files with deparsed source code.", null, true),
     EmitTmpHashed("Use an SHA-256 hash as file name to reduce temporary file creation.", true),
+    SpawnUsesPloyglot("use PolyglotEngine for .fastr.context.spwan", true),
 
     // Promises optimizations
     EagerEval("If enabled, overrides all other EagerEval switches (see EagerEvalHelper)", false),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ChildContextInfo.java
similarity index 75%
rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ChildContextInfo.java
index 57d153738c..bdcd6c61d3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ChildContextInfo.java
@@ -30,6 +30,7 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import com.oracle.truffle.api.TruffleContext;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.api.vm.PolyglotEngine.Builder;
 import com.oracle.truffle.r.launcher.RCmdOptions;
@@ -54,12 +55,16 @@ final class ConsoleHandlerOutputStream extends OutputStream {
 }
 
 /**
- * Represents custom initialization state for an R instance.
+ * Represents custom initialization state for a "spawned" R instance, that is one created by, e.g.,
+ * {@code .fastr.context.eval} and test contexts. In particular there is no {@link ChildContextInfo}
+ * for the initial context, whether created by the {@code R/RScript} command or whether invoked from
+ * another language.
+ *
+ * There are some legacy functions that still use {@link PolyglotEngine} but the new way is to use
+ * {@link TruffleContext}.
  *
- * Use {@link #createVM()} to apply this information to a newly-built {@link PolyglotEngine}
- * instance (it will be stored in the "fastrContextInfo" global symbol).
  */
-public final class ContextInfo {
+public final class ChildContextInfo {
     static final String CONFIG_KEY = "fastrContextInfo";
 
     static final AtomicInteger contextInfoIds = new AtomicInteger();
@@ -80,10 +85,11 @@ public final class ContextInfo {
     private final OutputStream stderr;
     private final int id;
     private final int multiSlotInd;
+    private TruffleContext truffleContext;
     private PolyglotEngine vm;
     public Executor executor;
 
-    private ContextInfo(RStartParams startParams, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr, TimeZone systemTimeZone, int id,
+    private ChildContextInfo(RStartParams startParams, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr, TimeZone systemTimeZone, int id,
                     int multiSlotInd) {
         this.startParams = startParams;
         this.env = env;
@@ -109,6 +115,16 @@ public final class ContextInfo {
         multiSlotInds.set(0); // to account for primordial context
     }
 
+    public TruffleContext createTruffleContext() {
+        this.truffleContext = RContext.getInstance().getEnv().newContextBuilder().config("parentContext", parent.getVM()).config(CONFIG_KEY, this).build();
+        return this.truffleContext;
+    }
+
+    public TruffleContext createVM(ChildContextInfo childContextInfo) {
+        this.truffleContext = RContext.getInstance().getEnv().newContextBuilder().config("parentContext", parent.getVM()).config(CONFIG_KEY, this).build();
+        return this.truffleContext;
+    }
+
     public PolyglotEngine createVM() {
         Builder builder = PolyglotEngine.newBuilder();
         if (startParams.isInteractive()) {
@@ -129,13 +145,14 @@ public final class ContextInfo {
     /**
      * Create a context configuration object.
      *
-     * @param startParams the start parameters passed this R session
+     * @param startParams the start parameters passed this spawned R session
      * @param kind defines the degree to which this context shares base and package environments
      *            with its parent
      * @param parent if non-null {@code null}, the parent creating the context
      * @param systemTimeZone the system's time zone
      */
-    public static ContextInfo create(RStartParams startParams, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr, TimeZone systemTimeZone) {
+    public static ChildContextInfo create(RStartParams startParams, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr,
+                    TimeZone systemTimeZone) {
         int id = contextInfoIds.incrementAndGet();
         int multiSlotInd = multiSlotInds.get();
         if (kind == ContextKind.SHARE_ALL || kind == ContextKind.SHARE_NOTHING) {
@@ -147,10 +164,10 @@ public final class ContextInfo {
             throw RInternalError.shouldNotReachHere();
         }
         assert kind != ContextKind.SHARE_PARENT_RW || (kind == ContextKind.SHARE_PARENT_RW && parent.getKind() == ContextKind.SHARE_NOTHING && parent.getMultiSlotInd() == 0);
-        return new ContextInfo(startParams, env, kind, parent, stdin, stdout, stderr, systemTimeZone, id, kind == ContextKind.SHARE_PARENT_RW ? 0 : multiSlotInd);
+        return new ChildContextInfo(startParams, env, kind, parent, stdin, stdout, stderr, systemTimeZone, id, kind == ContextKind.SHARE_PARENT_RW ? 0 : multiSlotInd);
     }
 
-    public static ContextInfo create(RStartParams startParams, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr) {
+    public static ChildContextInfo create(RStartParams startParams, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr) {
         return create(startParams, env, kind, parent, stdin, stdout, stderr, TimeZone.getDefault());
     }
 
@@ -163,7 +180,7 @@ public final class ContextInfo {
      *            with its parent
      * @param parent if non-null {@code null}, the parent creating the context
      */
-    public static ContextInfo createNoRestore(Client client, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr) {
+    public static ChildContextInfo createNoRestore(Client client, String[] env, ContextKind kind, RContext parent, InputStream stdin, OutputStream stdout, OutputStream stderr) {
         RStartParams params = new RStartParams(RCmdOptions.parseArguments(client, new String[]{"R", "--vanilla", "--slave", "--silent", "--no-restore"}, false), false);
         return create(params, env, kind, parent, stdin, stdout, stderr);
     }
@@ -196,6 +213,11 @@ public final class ContextInfo {
         return multiSlotInd;
     }
 
+    public TruffleContext getTruffleContext() {
+        return truffleContext;
+    }
+
+    @Deprecated
     public PolyglotEngine getVM() {
         return vm;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
index 104c27b4a7..8ad26ae5a0 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
@@ -237,4 +237,10 @@ public interface Engine {
      * Essentially this is equivalent to {@link #evalFunction} using the {@code "print"} function.
      */
     void printResult(Object value);
+
+    /**
+     * Return the "global" frame for this {@link Engine}, aka {@code globalEnv}.
+     *
+     */
+    MaterializedFrame getGlobalFrame();
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/EvalThread.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/EvalThread.java
index ac0107b5f7..d515b1d63d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/EvalThread.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/EvalThread.java
@@ -28,10 +28,12 @@ import java.util.concurrent.Semaphore;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.TruffleContext;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.r.runtime.ExitException;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -46,7 +48,9 @@ import com.oracle.truffle.r.runtime.data.RNull;
 public class EvalThread extends Thread {
 
     private final Source source;
-    private final ContextInfo info;
+    private final ChildContextInfo info;
+    private final TruffleContext truffleContext;
+    private final boolean usePolyglot;
     private RList evalResult;
     private Semaphore init = new Semaphore(0);
 
@@ -58,22 +62,37 @@ public class EvalThread extends Thread {
     /** We use a separate counter for threads since ConcurrentHashMap.size() is not reliable. */
     public static final AtomicInteger threadCnt = new AtomicInteger(0);
 
-    public EvalThread(ContextInfo info, Source source) {
+    public EvalThread(ChildContextInfo info, Source source) {
         this.info = info;
         this.source = source;
         threadCnt.incrementAndGet();
         threads.put(info.getId(), this);
         idToMultiSlotTable.put(info.getId(), info.getMultiSlotInd());
+        truffleContext = info.createTruffleContext();
+        usePolyglot = false;
+    }
+
+    public EvalThread(ChildContextInfo info, Source source, boolean usePolyglot) {
+        this.info = info;
+        this.source = source;
+        threadCnt.incrementAndGet();
+        threads.put(info.getId(), this);
+        idToMultiSlotTable.put(info.getId(), info.getMultiSlotInd());
+        this.usePolyglot = true;
+        truffleContext = null;
     }
 
     @Override
     public void run() {
-        PolyglotEngine vm = info.createVM(PolyglotEngine.newBuilder());
         init.release();
         try {
-            evalResult = run(vm, info, source);
+            if (usePolyglot) {
+                PolyglotEngine vm = info.createVM(PolyglotEngine.newBuilder());
+                evalResult = run(vm, info, source);
+            } else {
+                evalResult = run(truffleContext, info, source);
+            }
         } finally {
-            vm.dispose();
             threads.remove(info.getId());
             threadCnt.decrementAndGet();
         }
@@ -94,11 +113,40 @@ public class EvalThread extends Thread {
     /**
      * Convenience method for {@code .fastr.context.eval} in same thread.
      */
-    public static RList run(PolyglotEngine vm, ContextInfo info, Source source) {
+    public static RList run(TruffleContext truffleContext, ChildContextInfo info, Source source) {
+        RList result = null;
+        Object parent = null;
+        try {
+            parent = truffleContext.enter();
+            // this is the engine for the new child context
+            Engine rEngine = RContext.getEngine();
+            Object evalResult = rEngine.parseAndEval(source, rEngine.getGlobalFrame(), false);
+            result = createEvalResult(evalResult, false);
+        } catch (ParseException e) {
+            e.report(info.getStdout());
+            result = createErrorResult(e.getMessage());
+        } catch (ExitException e) {
+            // termination, treat this as "success"
+            result = RDataFactory.createList(new Object[]{e.getStatus()});
+        } catch (RError e) {
+            // nothing to do
+            result = RDataFactory.createList(new Object[]{RNull.instance});
+        } catch (Throwable t) {
+            // some internal error
+            RInternalError.reportErrorAndConsoleLog(t, info.getId());
+            result = createErrorResult(t.getClass().getSimpleName());
+        } finally {
+            truffleContext.leave(parent);
+            truffleContext.close();
+        }
+        return result;
+    }
+
+    public static RList run(PolyglotEngine vm, ChildContextInfo info, Source source) {
         RList evalResult;
         try {
             PolyglotEngine.Value resultValue = vm.eval(source);
-            evalResult = createEvalResult(resultValue);
+            evalResult = createEvalResult(resultValue, true);
         } catch (ParseException e) {
             e.report(info.getStdout());
             evalResult = createErrorResult(e.getMessage());
@@ -112,6 +160,8 @@ public class EvalThread extends Thread {
             // some internal error
             RInternalError.reportErrorAndConsoleLog(t, info.getId());
             evalResult = createErrorResult(t.getClass().getSimpleName());
+            // } finally {
+            // vm.close();
         }
         return evalResult;
     }
@@ -121,8 +171,7 @@ public class EvalThread extends Thread {
      * resulted in an error.
      */
     @TruffleBoundary
-    private static RList createEvalResult(PolyglotEngine.Value resultValue) {
-        Object result = resultValue.get();
+    private static RList createEvalResult(Object result, boolean usePolyglot) {
         Object listResult = result;
         String error = null;
         if (result == null) {
@@ -130,7 +179,11 @@ public class EvalThread extends Thread {
             listResult = RRuntime.LOGICAL_NA;
             error = "R error";
         } else if (result instanceof TruffleObject) {
-            listResult = resultValue.as(Object.class);
+            if (usePolyglot) {
+                listResult = ((PolyglotEngine.Value) result).as(Object.class);
+            } else {
+                throw RInternalError.unimplemented();
+            }
         } else {
             listResult = result;
         }
@@ -153,7 +206,7 @@ public class EvalThread extends Thread {
         return evalResult;
     }
 
-    public ContextInfo getContextInfo() {
+    public ChildContextInfo getContextInfo() {
         return info;
     }
 }
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 d9f72a3fe2..b6d94d8d5c 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
@@ -52,6 +52,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleContext;
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.TruffleLanguage.Env;
 import com.oracle.truffle.api.instrumentation.AllocationReporter;
@@ -106,7 +107,7 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
  *
  * Contexts are created during construction of the {@link PolyglotEngine} instance. In case a
  * context needs to be configured, the PolyglotEngine needs to be created via the
- * {@code RContextFactory} class, which takes a {@link ContextInfo} object for configuration.
+ * {@code RContextFactory} class, which takes a {@link ChildContextInfo} object for configuration.
  *
  * The context provides a so-called {@link Engine} (accessed via {@link #getEngine()}), which
  * provides basic parsing and execution functionality .
@@ -242,7 +243,9 @@ public final class RContext implements RTruffleObject {
     private final RContext parentContext;
     private final int id;
     private final int multiSlotIndex;
-    private PolyglotEngine polyglotEngine;
+    private TruffleContext truffleContext;
+    private PolyglotEngine vm;
+
     public Executor executor;
 
     private final InputStream stdin;
@@ -379,11 +382,11 @@ public final class RContext implements RTruffleObject {
             args = env.getApplicationArguments();
         }
 
-        Object initialInfo = env.getConfig().get(ContextInfo.CONFIG_KEY);
+        Object initialInfo = env.getConfig().get(ChildContextInfo.CONFIG_KEY);
         if (initialInfo == null) {
             /*
-             * This implies that FastR is being invoked initially from another Truffle language and
-             * not via RCommand/RscriptCommand. In this case, we also assume that no previously
+             * This implies that FastR is being invoked initially from another Truffle language or
+             * via RCommand/RscriptCommand. TODO How to deciden if session state is to be restored
              * stored session should be restored.
              */
             this.cmdOptions = RCmdOptions.parseArguments(Client.R, args, true);
@@ -392,12 +395,13 @@ public final class RContext implements RTruffleObject {
             this.contextKind = ContextKind.SHARE_NOTHING;
             this.systemTimeZone = TimeZone.getDefault();
             this.parentContext = null;
-            this.id = ContextInfo.contextInfoIds.incrementAndGet();
+            this.id = ChildContextInfo.contextInfoIds.incrementAndGet();
             this.multiSlotIndex = 0;
-            this.polyglotEngine = null;
+            this.truffleContext = null; // TODO
             this.executor = null;
         } else {
-            ContextInfo info = (ContextInfo) initialInfo;
+            // child spawned explicitly by R
+            ChildContextInfo info = (ChildContextInfo) initialInfo;
             this.cmdOptions = RCmdOptions.parseArguments(Client.R, args, true);
             this.startParameters = info.getStartParams();
             this.environment = info.getEnv();
@@ -406,7 +410,7 @@ public final class RContext implements RTruffleObject {
             this.parentContext = info.getParent();
             this.id = info.getId();
             this.multiSlotIndex = info.getMultiSlotInd();
-            this.polyglotEngine = info.getVM();
+            this.truffleContext = info.getTruffleContext();
             this.executor = info.executor;
         }
 
@@ -752,8 +756,12 @@ public final class RContext implements RTruffleObject {
         return stateRFFI;
     }
 
+    public TruffleContext getTruffleContext() {
+        return truffleContext;
+    }
+
     public PolyglotEngine getVM() {
-        return polyglotEngine;
+        return vm;
     }
 
     public boolean isInitial() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
index 5f055784b2..a4c446d704 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.StableValue;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RPromise;
 
@@ -463,11 +463,11 @@ public final class FrameSlotChangeMonitor {
         private final Object[] data;
 
         public MultiSlotData(MultiSlotData prevValue) {
-            data = Arrays.copyOf(prevValue.data, ContextInfo.contextNum());
+            data = Arrays.copyOf(prevValue.data, ChildContextInfo.contextNum());
         }
 
         public MultiSlotData() {
-            data = new Object[ContextInfo.contextNum()];
+            data = new Object[ChildContextInfo.contextNum()];
         }
 
         public Object get(int ind) {
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
index 7244ad0a29..3e8c47797a 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ResourceHandlerFactory;
 import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.test.generate.FastRSession;
@@ -630,7 +630,7 @@ public class TestBase {
     private boolean evalAndCompare(String[] inputs, TestTrait... traitsList) {
         WhiteList[] whiteLists = TestTrait.collect(traitsList, WhiteList.class);
         TestTraitsSet traits = new TestTraitsSet(traitsList);
-        ContextInfo contextInfo = traits.context.contains(Context.NonShared) ? fastROutputManager.fastRSession.createContextInfo(ContextKind.SHARE_NOTHING) : null;
+        ChildContextInfo contextInfo = traits.context.contains(Context.NonShared) ? fastROutputManager.fastRSession.createContextInfo(ContextKind.SHARE_NOTHING) : null;
         int index = 1;
         boolean allOk = true;
         boolean skipFastREval = traits.isIgnored || generatingExpected();
@@ -972,7 +972,7 @@ public class TestBase {
      * Evaluate {@code input} in FastR, returning all (virtual) console output that was produced. If
      * {@code nonShared} then this must evaluate in a new, non-shared, {@link RContext}.
      */
-    protected String fastREval(String input, ContextInfo contextInfo, boolean longTimeout) {
+    protected String fastREval(String input, ChildContextInfo contextInfo, boolean longTimeout) {
         microTestInfo.expression = input;
         String result;
         try {
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 2b3cf0a5fb..4770f9db91 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RSource;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 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;
@@ -98,9 +98,9 @@ public final class FastRSession implements RSession {
 
     public static final Source GET_CONTEXT = RSource.fromTextInternal("invisible(.fastr.context.get())", RSource.Internal.GET_CONTEXT);
 
-    public ContextInfo checkContext(ContextInfo contextInfoArg) {
+    public ChildContextInfo checkContext(ChildContextInfo contextInfoArg) {
         create();
-        ContextInfo contextInfo;
+        ChildContextInfo contextInfo;
         if (contextInfoArg == null) {
             contextInfo = createContextInfo(ContextKind.SHARE_PARENT_RW);
         } else {
@@ -109,9 +109,9 @@ public final class FastRSession implements RSession {
         return contextInfo;
     }
 
-    public ContextInfo createContextInfo(ContextKind contextKind) {
+    public ChildContextInfo createContextInfo(ContextKind contextKind) {
         RStartParams params = new RStartParams(RCmdOptions.parseArguments(Client.R, new String[]{"R", "--vanilla", "--slave", "--silent", "--no-restore"}, false), false);
-        return ContextInfo.create(params, null, contextKind, mainContext, input, output, output, TimeZone.getTimeZone("GMT"));
+        return ChildContextInfo.create(params, null, contextKind, mainContext, input, output, output, TimeZone.getTimeZone("GMT"));
     }
 
     private FastRSession() {
@@ -128,7 +128,7 @@ public final class FastRSession implements RSession {
         }
         try {
             RStartParams params = new RStartParams(RCmdOptions.parseArguments(Client.R, new String[]{"R", "--vanilla", "--slave", "--silent", "--no-restore"}, false), false);
-            ContextInfo info = ContextInfo.create(params, null, ContextKind.SHARE_NOTHING, null, input, output, output);
+            ChildContextInfo info = ChildContextInfo.create(params, null, ContextKind.SHARE_NOTHING, null, input, output, output);
             main = info.createVM();
             mainContext = main.eval(GET_CONTEXT).as(RContext.class);
         } finally {
@@ -181,12 +181,12 @@ public final class FastRSession implements RSession {
     }
 
     @Override
-    public String eval(TestBase testClass, String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable {
+    public String eval(TestBase testClass, String expression, ChildContextInfo contextInfo, boolean longTimeout) throws Throwable {
         Timer timer = null;
         output.reset();
         input.setContents(expression);
         try {
-            ContextInfo actualContextInfo = checkContext(contextInfo);
+            ChildContextInfo actualContextInfo = checkContext(contextInfo);
             // set up some interop objects used by fastr-specific tests:
             PolyglotEngine.Builder builder = PolyglotEngine.newBuilder();
             if (testClass != null) {
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
index d80b8dd069..8c6ba569e2 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
@@ -32,7 +32,7 @@ import java.util.concurrent.TimeUnit;
 import com.oracle.truffle.r.launcher.RVersionNumber;
 import com.oracle.truffle.r.runtime.ProcessOutputManager;
 import com.oracle.truffle.r.runtime.REnvVars;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 import com.oracle.truffle.r.test.TestBase;
 
 /**
@@ -93,7 +93,7 @@ public class GnuROneShotRSession implements RSession {
     }
 
     @Override
-    public String eval(TestBase testBase, String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable {
+    public String eval(TestBase testBase, String expression, ChildContextInfo contextInfo, boolean longTimeout) throws Throwable {
         if (expression.contains("library(") && !TestBase.generatingExpected()) {
             System.out.println("==============================================");
             System.out.println("LIBRARY LOADING WHEN NOT GENERATING EXPECTED OUTPUT");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java
index 40e96af850..6783accf75 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/RSession.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.test.generate;
 
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 import com.oracle.truffle.r.test.TestBase;
 
 /**
@@ -42,7 +42,7 @@ public interface RSession {
      * This result will always be non-null or an exception will be thrown in, say, a timeout
      * occurring.
      */
-    String eval(TestBase testClass, String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable;
+    String eval(TestBase testClass, String expression, ChildContextInfo contextInfo, boolean longTimeout) throws Throwable;
 
     /**
      * A name to identify the session.
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
index 4a25a0082b..a419f8ff22 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
@@ -54,7 +54,7 @@ import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.api.vm.PolyglotEngine.Value;
 import com.oracle.truffle.r.launcher.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RSource;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.ChildContextInfo;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.runtime.data.RPromise.EagerPromise;
 import com.oracle.truffle.r.runtime.env.REnvironment;
@@ -74,7 +74,7 @@ public class FastRDebugTest {
     public void before() {
         suspendedEvent = null;
 
-        ContextInfo info = ContextInfo.createNoRestore(Client.R, null, ContextKind.SHARE_NOTHING, null, System.in, out, err);
+        ChildContextInfo info = ChildContextInfo.createNoRestore(Client.R, null, ContextKind.SHARE_NOTHING, null, System.in, out, err);
         engine = info.createVM(PolyglotEngine.newBuilder().setOut(out).setErr(err));
         debugger = Debugger.find(engine);
         debuggerSession = debugger.startSession(event -> {
diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py
index adb4b56741..ce442915dc 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -29,7 +29,7 @@ suite = {
             {
                "name" : "truffle",
                "subdir" : True,
-               "version" : "b7848be486a979673f6f695b9b0ca78b2e0d9164",
+               "version" : "554cf703833b2665da613da0fac4972abd293fbd",
                "urls" : [
                     {"url" : "https://github.com/graalvm/graal", "kind" : "git"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
-- 
GitLab