diff --git a/.gitignore b/.gitignore
index a1b4ad8c171c249f4b64de267405318c95a4df97..d39a0a4a07f33856d938f8873ce7daafa0d520c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,6 +81,7 @@ scratch/
 bin/
 share/
 etc/
+doc/
 src_gen/
 /local/
 /.hgtip
@@ -113,3 +114,5 @@ test_gnur
 test_fastr
 lib.install.cran*
 package.blacklist
+com.oracle.truffle.r.test.native/embedded/lib
+
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 324acbd6cba2cbf408769fdf21415dba05efc0f2..62a3e4bb2b873db16ebc06b620aced31690a5563 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
@@ -56,17 +56,17 @@ import com.oracle.truffle.r.nodes.control.BreakException;
 import com.oracle.truffle.r.nodes.control.NextException;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
-import com.oracle.truffle.r.runtime.BrowserQuitException;
+import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
-import com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RErrorHandling;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RParserFactory;
 import com.oracle.truffle.r.runtime.RProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
@@ -177,9 +177,9 @@ final class REngine implements Engine, Engine.Timings {
                     throw new RInternalError(e, "error while parsing user profile from %s", userProfile.getName());
                 }
             }
-            if (!(context.getOptions().getBoolean(RCmdOption.NO_RESTORE) || context.getOptions().getBoolean(RCmdOption.NO_RESTORE_DATA))) {
+            if (!(context.getStartParams().getRestoreAction() == SA_TYPE.NORESTORE)) {
                 // call sys.load.image(".RData", RCmdOption.QUIET
-                checkAndRunStartupShutdownFunction("sys.load.image", new String[]{"\".RData\"", context.getOptions().getBoolean(RCmdOption.QUIET) ? "TRUE" : "FALSE"});
+                checkAndRunStartupShutdownFunction("sys.load.image", new String[]{"\".RData\"", context.getStartParams().getQuiet() ? "TRUE" : "FALSE"});
                 context.getConsoleHandler().setHistoryFrom(new File("./.Rhistory"));
             }
             checkAndRunStartupShutdownFunction(".First");
@@ -247,7 +247,7 @@ final class REngine implements Engine, Engine.Timings {
             return lastValue;
         } catch (ReturnException ex) {
             return ex.getResult();
-        } catch (DebugExitException | BrowserQuitException e) {
+        } catch (DebugExitException | JumpToTopLevelException e) {
             throw e;
         } catch (RError e) {
             // RError prints the correct result on the console during construction
@@ -322,7 +322,7 @@ final class REngine implements Engine, Engine.Timings {
                 return lastValue;
             } catch (ReturnException ex) {
                 return ex.getResult();
-            } catch (DebugExitException | BrowserQuitException | ThreadDeath e) {
+            } catch (DebugExitException | JumpToTopLevelException | ThreadDeath e) {
                 throw e;
             } catch (RError e) {
                 // TODO normal error reporting is done by the runtime
@@ -507,7 +507,7 @@ final class REngine implements Engine, Engine.Timings {
                     // there can be an outer loop
                     throw cfe;
                 }
-            } catch (DebugExitException | BrowserQuitException e) {
+            } catch (DebugExitException | JumpToTopLevelException e) {
                 CompilerDirectives.transferToInterpreter();
                 throw e;
             } catch (Throwable e) {
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
index 1cc9f5502c982708473f2bfa859f3c34486382a9..29700d0b926722999fa95f84fde571c2ebeb4468 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
@@ -582,11 +582,6 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         return RASTUtils.unwrap(promise.getRep()).asRSyntaxNode();
     }
 
-    @Override
-    public void enableDebug(RFunction func) {
-        DebugHandling.enableDebug(func, "", RNull.instance, false);
-    }
-
     @Override
     public boolean isTaggedWith(Node node, Class<?> tag) {
         if (!(node instanceof RSyntaxNode)) {
@@ -649,4 +644,19 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         return ConstantNode.create(o);
     }
 
+    @Override
+    public boolean enableDebug(RFunction func, boolean once) {
+        return DebugHandling.enableDebug(func, "", RNull.instance, once);
+    }
+
+    @Override
+    public boolean isDebugged(RFunction func) {
+        return DebugHandling.isDebugged(func);
+    }
+
+    @Override
+    public boolean disableDebug(RFunction func) {
+        return DebugHandling.undebug(func);
+    }
+
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
index eb289f24e94b5c7bf7fecf85f13d132e7e1b5027..e1cee8110744a8b7a5ce61a369499790c44c4af8 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
@@ -76,7 +76,7 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
             RPackageSource.initialize();
             RContext.initialize(new RASTBuilder(), new RRuntimeASTAccessImpl(), RBuiltinPackages.getInstance(), new RForeignAccessFactoryImpl());
         } catch (Throwable t) {
-            System.out.println("error during engine initialization:");
+            System.err.println("error during engine initialization: " + t);
             t.printStackTrace();
             System.exit(-1);
         }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e5040ee582fd8423eda42aeb596e77094ab5c8d
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2014, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.shell;
+
+import com.oracle.truffle.r.runtime.RInterfaceCallbacks;
+import com.oracle.truffle.r.runtime.RStartParams;
+import com.oracle.truffle.r.runtime.context.ConsoleHandler;
+import com.oracle.truffle.r.runtime.context.DefaultConsoleHandler;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+
+/**
+ * In embedded mode the console functions as defined in {@code Rinterface.h} can be overridden. This
+ * class supports that, delegating to a standard console handler if not redirected.
+ *
+ * N.B. At the time the constructor is created, we do not know if the console is overridden so we
+ * have be lazy about that.
+ *
+ */
+public class EmbeddedConsoleHandler implements ConsoleHandler {
+
+    private final RStartParams startParams;
+    /**
+     * Only not {@code null} when console is not overridden.
+     */
+    private ConsoleHandler delegate;
+    private REmbedRFFI rEmbedRFFI;
+    private String prompt;
+
+    EmbeddedConsoleHandler(RStartParams startParams) {
+        this.startParams = startParams;
+    }
+
+    private REmbedRFFI getREmbedRFFI() {
+        if (rEmbedRFFI == null) {
+            rEmbedRFFI = RFFIFactory.getRFFI().getREmbedRFFI();
+            if (!(RInterfaceCallbacks.R_WriteConsole.isOverridden() || RInterfaceCallbacks.R_ReadConsole.isOverridden())) {
+                if (startParams.getNoReadline()) {
+                    delegate = new DefaultConsoleHandler(System.in, System.out);
+                } else {
+                    delegate = new JLineConsoleHandler(startParams);
+                }
+            }
+        }
+        return rEmbedRFFI;
+    }
+
+    @Override
+    public void println(String s) {
+        getREmbedRFFI();
+        if (delegate == null) {
+            getREmbedRFFI().writeConsole(s);
+            getREmbedRFFI().writeConsole("\n");
+        } else {
+            delegate.println(s);
+        }
+
+    }
+
+    @Override
+    public void print(String s) {
+        getREmbedRFFI();
+        if (delegate == null) {
+            rEmbedRFFI.writeConsole(s);
+        } else {
+            delegate.print(s);
+        }
+
+    }
+
+    @Override
+    public void printErrorln(String s) {
+        getREmbedRFFI();
+        if (delegate == null) {
+            rEmbedRFFI.writeErrConsole(s);
+            rEmbedRFFI.writeErrConsole("\n");
+        } else {
+            delegate.printErrorln(s);
+        }
+
+    }
+
+    @Override
+    public void printError(String s) {
+        getREmbedRFFI();
+        if (delegate == null) {
+            rEmbedRFFI.writeErrConsole(s);
+        } else {
+            delegate.printError(s);
+        }
+
+    }
+
+    @Override
+    public String readLine() {
+        getREmbedRFFI();
+        if (delegate == null) {
+            return rEmbedRFFI.readConsole(prompt);
+        } else {
+            return delegate.readLine();
+        }
+    }
+
+    @Override
+    public boolean isInteractive() {
+        return startParams.getInteractive();
+    }
+
+    @Override
+    public String getPrompt() {
+        return prompt;
+    }
+
+    @Override
+    public void setPrompt(String prompt) {
+        this.prompt = prompt;
+        if (delegate != null) {
+            delegate.setPrompt(prompt);
+        }
+
+    }
+
+    @Override
+    public String getInputDescription() {
+        return "<embedded input>";
+    }
+
+}
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
index 0c5cdcd86f9305b26df4fac1ccff5bb2c7ba34c0..0369266b8df75d613c28c63de810f3a5037f745a 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
@@ -27,10 +27,10 @@ import java.io.IOException;
 import java.io.PrintWriter;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
-import com.oracle.truffle.r.runtime.context.RContext;
 
 import jline.console.ConsoleReader;
 import jline.console.UserInterruptException;
@@ -42,10 +42,17 @@ class JLineConsoleHandler implements ConsoleHandler {
     private final boolean isInteractive;
     private final PrintWriter printWriter;
 
-    JLineConsoleHandler(boolean isInteractive, ConsoleReader console) {
-        this.console = console;
+    JLineConsoleHandler(RStartParams startParams) {
+        try {
+            console = new ConsoleReader(System.in, System.out);
+            console.setHandleUserInterrupt(true);
+            console.setExpandEvents(false);
+        } catch (IOException ex) {
+            throw Utils.fail("unexpected error opening console reader");
+        }
+        // long start = System.currentTimeMillis();
         printWriter = new PrintWriter(console.getOutput());
-        this.isInteractive = isInteractive;
+        this.isInteractive = startParams.getInteractive();
     }
 
     @Override
@@ -108,11 +115,6 @@ class JLineConsoleHandler implements ConsoleHandler {
         console.setPrompt(prompt);
     }
 
-    @Override
-    public int getWidth() {
-        return RContext.CONSOLE_WIDTH;
-    }
-
     @Override
     public String getInputDescription() {
         return RSource.Internal.SHELL_INPUT.string;
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java
index 3911f4468da9e666304337ef8daead8ddaa8ec5c..5452a324b63f0696df3c7fa271254cf108344825 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java
@@ -25,23 +25,10 @@ package com.oracle.truffle.r.engine.shell;
 import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.EXPR;
 import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.FILE;
 import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.INTERACTIVE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_ENVIRON;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_INIT_FILE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_READLINE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_RESTORE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_SAVE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.QUIET;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.SAVE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.SILENT;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.SLAVE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.VANILLA;
-
 import java.io.Console;
 import java.io.EOFException;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.nio.file.Files;
 import java.util.List;
 
@@ -49,12 +36,14 @@ 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.nodes.builtin.base.Quit;
-import com.oracle.truffle.r.runtime.BrowserQuitException;
+import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
 import com.oracle.truffle.r.runtime.Utils.DebugExitException;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.ContextInfo;
@@ -65,7 +54,6 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 
-import jline.console.ConsoleReader;
 import jline.console.UserInterruptException;
 
 /**
@@ -76,42 +64,48 @@ public class RCommand {
     // CheckStyle: stop system..print check
 
     public static void main(String[] args) {
-        RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args);
+        RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args, false);
         options.printHelpAndVersion();
-        ContextInfo info = createContextInfoFromCommandLine(options);
+        PolyglotEngine vm = createPolyglotEngineFromCommandLine(options, false);
         // never returns
-        readEvalPrint(info);
+        readEvalPrint(vm);
         throw RInternalError.shouldNotReachHere();
     }
 
-    static ContextInfo createContextInfoFromCommandLine(RCmdOptions options) {
-        if (options.getBoolean(SLAVE)) {
-            options.setValue(QUIET, true);
-            options.setValue(NO_SAVE, true);
-        }
+    /**
+     * The standard R script escapes spaces to "~+~" in "-e" and "-f" commands.
+     */
+    private static String unescapeSpace(String input) {
+        return input.replace("~+~", " ");
+    }
 
-        if (options.getBoolean(VANILLA)) {
-            options.setValue(NO_SAVE, true);
-            options.setValue(NO_ENVIRON, true);
-            options.setValue(NO_INIT_FILE, true);
-            options.setValue(NO_RESTORE, true);
-        }
+    static PolyglotEngine createPolyglotEngineFromCommandLine(RCmdOptions options, boolean embedded) {
+        RStartParams rsp = new RStartParams(options, embedded);
 
         String fileArg = options.getString(FILE);
         if (fileArg != null) {
             if (options.getStringList(EXPR) != null) {
-                Utils.fatalError("cannot use -e with -f or --file");
+                Utils.rSuicide("cannot use -e with -f or --file");
             }
-            if (!options.getBoolean(SLAVE)) {
-                options.setValue(NO_SAVE, true);
+            if (!rsp.getSlave()) {
+                rsp.setSaveAction(SA_TYPE.NOSAVE);
             }
             if (fileArg.equals("-")) {
                 // means stdin, but still implies NO_SAVE
                 fileArg = null;
+            } else {
+                fileArg = unescapeSpace(fileArg);
             }
+            // cf GNU R
+            rsp.setInteractive(false);
         }
 
-        if (!(options.getBoolean(QUIET) || options.getBoolean(SILENT))) {
+        /*
+         * Outputting the welcome message here has the virtue that the VM initialization delay
+         * occurs later. However, it does not work in embedded mode as console redirects have not
+         * been installed at this point. So we do it later in REmbedded.
+         */
+        if (!rsp.getQuiet() && !embedded) {
             System.out.println(RRuntime.WELCOME_MESSAGE);
         }
         /*
@@ -120,8 +114,6 @@ public class RCommand {
          * checked.
          */
         ConsoleHandler consoleHandler;
-        InputStream consoleInput = System.in;
-        OutputStream consoleOutput = System.out;
         if (fileArg != null) {
             List<String> lines;
             String filePath;
@@ -130,45 +122,47 @@ public class RCommand {
                 lines = Files.readAllLines(file.toPath());
                 filePath = file.getCanonicalPath();
             } catch (IOException e) {
-                throw Utils.fatalError("cannot open file '" + fileArg + "': " + e.getMessage());
+                throw Utils.rSuicide("cannot open file '" + fileArg + "': " + e.getMessage());
             }
             consoleHandler = new StringConsoleHandler(lines, System.out, filePath);
         } else if (options.getStringList(EXPR) != null) {
             List<String> exprs = options.getStringList(EXPR);
-            if (!options.getBoolean(SLAVE)) {
-                options.setValue(NO_SAVE, true);
+            for (int i = 0; i < exprs.size(); i++) {
+                exprs.set(i, unescapeSpace(exprs.get(i)));
+            }
+            if (!rsp.getSlave()) {
+                rsp.setSaveAction(SA_TYPE.NOSAVE);
             }
+            // cf GNU R
+            rsp.setInteractive(false);
             consoleHandler = new StringConsoleHandler(exprs, System.out, RSource.Internal.EXPRESSION_INPUT.string);
         } else {
             /*
              * GnuR behavior differs from the manual entry for {@code interactive} in that {@code
              * --interactive} never applies to {@code -e/-f}, only to console input that has been
              * redirected from a pipe/file etc.
+             *
+             * 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.
              */
             Console sysConsole = System.console();
-            boolean useReadLine = !options.getBoolean(NO_READLINE);
-            ConsoleReader consoleReader = null;
-            if (useReadLine) {
-                try {
-                    consoleReader = new ConsoleReader(consoleInput, consoleOutput);
-                    consoleReader.setHandleUserInterrupt(true);
-                    consoleReader.setExpandEvents(false);
-                } catch (IOException ex) {
-                    throw Utils.fail("unexpected error opening console reader");
-                }
-            }
             boolean isInteractive = options.getBoolean(INTERACTIVE) || sysConsole != null;
-            if (!isInteractive && !options.getBoolean(SAVE) && !options.getBoolean(NO_SAVE) && !options.getBoolean(VANILLA)) {
-                throw Utils.fatalError("you must specify '--save', '--no-save' or '--vanilla'");
+            if (!isInteractive && rsp.getSaveAction() != SA_TYPE.SAVE && rsp.getSaveAction() != SA_TYPE.NOSAVE) {
+                throw Utils.rSuicide("you must specify '--save', '--no-save' or '--vanilla'");
             }
-            // long start = System.currentTimeMillis();
-            if (useReadLine) {
-                consoleHandler = new JLineConsoleHandler(isInteractive, consoleReader);
+            if (embedded) {
+                consoleHandler = new EmbeddedConsoleHandler(rsp);
             } else {
-                consoleHandler = new DefaultConsoleHandler(consoleInput, consoleOutput);
+                boolean useReadLine = !rsp.getNoReadline();
+                if (useReadLine) {
+                    consoleHandler = new JLineConsoleHandler(rsp);
+                } else {
+                    consoleHandler = new DefaultConsoleHandler(System.in, System.out);
+                }
             }
         }
-        return ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler);
+        return ContextInfo.create(rsp, ContextKind.SHARE_NOTHING, null, consoleHandler).createVM();
     }
 
     private static final Source GET_ECHO = RSource.fromTextInternal("invisible(getOption('echo'))", RSource.Internal.GET_ECHO);
@@ -185,9 +179,8 @@ public class RCommand {
      * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before
      * exiting. So,in either case, we never return.
      */
-    static void readEvalPrint(ContextInfo info) {
-        PolyglotEngine vm = info.createVM();
-        ConsoleHandler consoleHandler = info.getConsoleHandler();
+    static void readEvalPrint(PolyglotEngine vm) {
+        ConsoleHandler consoleHandler = ContextInfo.getContextInfo(vm).getConsoleHandler();
         try {
             // console.println("initialize time: " + (System.currentTimeMillis() - start));
             REPL: for (;;) {
@@ -235,7 +228,7 @@ public class RCommand {
                              * them explicitly
                              */
                             Throwable cause = e.getCause();
-                            if (cause instanceof BrowserQuitException) {
+                            if (cause instanceof JumpToTopLevelException) {
                                 // drop through to continue REPL
                             } else if (cause instanceof DebugExitException) {
                                 throw (RuntimeException) cause;
@@ -245,15 +238,12 @@ public class RCommand {
                                  * logging the report will go to a file, so we print a message on
                                  * the console as well.
                                  */
-                                consoleHandler.println("internal error: " + e.getMessage() + " (see fastr_errors.log)");
                                 RInternalError.reportError(e);
+                                consoleHandler.println("internal error: " + e.getMessage() + " (see fastr_errors.log)");
                             } else {
-                                /*
-                                 * This should never happen owing to earlier invariants of
-                                 * converting everything else to an RInternalError
-                                 */
-                                consoleHandler.println("unexpected internal error (" + e.getClass().getSimpleName() + "); " + e.getMessage());
+                                // Something else, e.g. NPE
                                 RInternalError.reportError(e);
+                                consoleHandler.println("unexpected internal error (" + e.getClass().getSimpleName() + "); " + e.getMessage());
                             }
                         }
                         continue REPL;
@@ -262,7 +252,7 @@ public class RCommand {
                     // interrupted by ctrl-c
                 }
             }
-        } catch (BrowserQuitException e) {
+        } catch (JumpToTopLevelException e) {
             // can happen if user profile invokes browser (unlikely but possible)
         } catch (EOFException ex) {
             try {
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
new file mode 100644
index 0000000000000000000000000000000000000000..ef6a876f10150a83939e57140cd3f8ff2e60ae45
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.shell;
+
+import java.io.IOException;
+
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+import com.oracle.truffle.r.runtime.RCmdOptions;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RSource;
+import com.oracle.truffle.r.runtime.RStartParams;
+import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.RContext;
+
+/**
+ * Support for embedding FastR in a C/C++ application according to {@code Rembedded.h}. The
+ * embedding interface consists of several functions and can be used in several ways. Since it is
+ * not specified other than by example, we only have existing use-cases to work from. This is the
+ * sequence used by {@code RStudio}.
+ *
+ * <pre>
+ * Rf_initialize_R(argv, args);
+ * Rstart rs;
+ * // set some rs fields
+ * R_SetParams(rs);
+ * // set some Rinterface function callbacks
+ * ptr_R_WriteConsole = local_R_WriteConsole
+ * Rf_mainloop();
+ * </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(PolyglotEngine)} and then
+ * {@link #runRmainloop(PolyglotEngine)}, which will complete the FastR initialization and enter the
+ * read-eval-print loop.
+ */
+public class REmbedded {
+
+    /**
+     * Creates the {@link PolyglotEngine} and initializes it. Called from native code when FastR is
+     * embedded. Corresponds to FFI method {@code Rf_initialize_R}. N.B. This does not completely
+     * initialize FastR as we cannot do that until the embedding system has had a chance to adjust
+     * the {@link RStartParams}, which happens after this call returns.
+     */
+    private static PolyglotEngine initializeR(String[] args) {
+        RContext.setEmbedded();
+        RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args, true);
+        PolyglotEngine vm = RCommand.createPolyglotEngineFromCommandLine(options, true);
+        try {
+            vm.eval(INIT);
+        } catch (IOException ex) {
+            Utils.rSuicide("initializeR");
+        }
+        return vm;
+    }
+
+    private static final Source INIT = RSource.fromTextInternal("1", RSource.Internal.GET_ECHO);
+
+    /**
+     * GnuR distinguishes {@code setup_Rmainloop} and {@code run_Rmainloop}. Currently we don't have
+     * the equivalent separation in FastR.
+     */
+    private static void setupRmainloop(@SuppressWarnings("unused") PolyglotEngine vm) {
+    }
+
+    /**
+     * This is where we can complete the initialization based on what modifications were made by the
+     * native code after {@link #initializeR} returned.
+     */
+    private static void runRmainloop(PolyglotEngine vm) {
+        RContext.getInstance().completeEmbeddedInitialization();
+        if (!RContext.getInstance().getStartParams().getQuiet()) {
+            RContext.getInstance().getConsoleHandler().println(RRuntime.WELCOME_MESSAGE);
+        }
+        RCommand.readEvalPrint(vm);
+    }
+
+    /**
+     * Testing vehicle, emulates a native upcall.
+     */
+    public static void main(String[] args) {
+        PolyglotEngine vm = initializeR(args);
+        RStartParams startParams = ContextInfo.getContextInfo(vm).getStartParams();
+        startParams.setEmbedded();
+        startParams.setLoadInitFile(false);
+        startParams.setNoRenviron(true);
+        setupRmainloop(vm);
+        runRmainloop(vm);
+    }
+
+    // Checkstyle: stop method name check
+
+    /**
+     * Upcalled from embedded mode to commit suicide.
+     */
+    @SuppressWarnings("unused")
+    private static void R_Suicide(String msg) {
+        Utils.exit(2);
+    }
+
+}
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java
index 0039a35912cdde32906fcd7f142f17f3dae33837..300f52e8acdf1ff2ae261947351ff9ba36d515bc 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RscriptCommand.java
@@ -31,10 +31,10 @@ import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.VERSION;
 
 import java.util.ArrayList;
 
+import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RVersionNumber;
-import com.oracle.truffle.r.runtime.context.ContextInfo;
 
 /**
  * Emulates the (Gnu)Rscript command as precisely as possible. in GnuR, Rscript is a genuine wrapper
@@ -99,11 +99,11 @@ public class RscriptCommand {
     public static void main(String[] args) {
         // Since many of the options are shared parse them from an RSCRIPT perspective.
         // Handle --help and --version specially, as they exit.
-        RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.RSCRIPT, args);
+        RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.RSCRIPT, args, false);
         preprocessRScriptOptions(options);
-        ContextInfo info = RCommand.createContextInfoFromCommandLine(options);
+        PolyglotEngine vm = RCommand.createPolyglotEngineFromCommandLine(options, false);
         // never returns
-        RCommand.readEvalPrint(info);
+        RCommand.readEvalPrint(vm);
         throw RInternalError.shouldNotReachHere();
     }
 
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java
index d4ae7a9942344952296ad1730d134fef590bbc33..e2edc533d17467e02b41229e6293bc86c379f220 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java
@@ -27,7 +27,6 @@ import java.util.List;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
-import com.oracle.truffle.r.runtime.context.RContext;
 
 class StringConsoleHandler implements ConsoleHandler {
     private final PrintStream output;
@@ -99,11 +98,6 @@ class StringConsoleHandler implements ConsoleHandler {
         this.prompt = prompt;
     }
 
-    @Override
-    public int getWidth() {
-        return RContext.CONSOLE_WIDTH;
-    }
-
     @Override
     public String getInputDescription() {
         return inputDescription;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b4d80c96f3f3d8b085cf7f2a706ebb056a7eba9
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.library.utils;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.library.utils.ObjectSizeNodeGen.RecursiveObjectSizeNodeGen;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributes;
+import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RComplexVector;
+import com.oracle.truffle.r.runtime.data.RDoubleSequence;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExpression;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RIntSequence;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RLanguage;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RLogicalVector;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.RRawVector;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+
+/*
+ * Similarly to GNU R's version, this is very approximate
+ * (e.g. overhead related to Java object headers is not included)
+ * and is only (semi) accurate for atomic vectors.
+ */
+public abstract class ObjectSize extends RExternalBuiltinNode.Arg1 {
+
+    protected abstract int executeInt(Object o);
+
+    @Child RecursiveObjectSize recursiveObjectSize;
+
+    protected int recursiveObjectSize(Object o) {
+        if (recursiveObjectSize == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursiveObjectSize = insert(RecursiveObjectSizeNodeGen.create());
+        }
+        return recursiveObjectSize.executeInt(o);
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") RNull o) {
+        return 64; // pointer?
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") int o) {
+        return 32;
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") double o) {
+        return 64;
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") byte o) {
+        return 8;
+    }
+
+    @Specialization
+    protected int objectSize(String o) {
+        return o.length() * 16;
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") RRaw o) {
+        return 8;
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") RComplex o) {
+        return 128;
+    }
+
+    @Specialization
+    protected int objectSize(RIntSequence o) {
+        int res = 96; // int length + int start + int stride
+        return res + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(RDoubleSequence o) {
+        int res = 160; // int length + double start + double stride
+        return res + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(RIntVector o) {
+        return o.getLength() * 32 + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(RDoubleVector o) {
+        return o.getLength() * 64 + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(RStringVector o) {
+        int res = 0;
+        for (int i = 0; i < o.getLength(); i++) {
+            res += o.getLength() * 16;
+        }
+        return res + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(RLogicalVector o) {
+        return o.getLength() * 8 + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(RComplexVector o) {
+        return o.getLength() * 128 + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(RRawVector o) {
+        return o.getLength() * 8 + attrSize(o);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    protected int objectSize(RList o) {
+        int res = 0;
+        for (int i = 0; i < o.getLength(); i++) {
+            res += recursiveObjectSize(o.getDataAt(i));
+        }
+        return res + attrSize(o);
+    }
+
+    @Specialization
+    @TruffleBoundary
+    protected int objectSize(RPairList o) {
+        RPairList list = o;
+        Object car = list.car();
+        int res = 0;
+        while (true) {
+            res += recursiveObjectSize(car);
+            Object cdr = list.cdr();
+            if (cdr == RNull.instance) {
+                break;
+            } else {
+                list = (RPairList) cdr;
+                car = list.car();
+            }
+        }
+        return res + attrSize(o);
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") RFunction o) {
+        return 256; // arbitrary, but does it really matter?
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") RLanguage o) {
+        return 256; // arbitrary, but does it really matter?
+    }
+
+    @Specialization
+    protected int objectSize(@SuppressWarnings("unused") RExpression o) {
+        return 256; // arbitrary, but does it really matter?
+    }
+
+    protected int attrSize(RAttributable o) {
+        return o.getAttributes() == null ? 0 : attrSizeInternal(o.getAttributes());
+    }
+
+    @TruffleBoundary
+    protected int attrSizeInternal(RAttributes attributes) {
+        int size = 0;
+        for (RAttribute attr : attributes) {
+            size += attr.getName().length() * 16;
+            size += recursiveObjectSize(attr.getValue());
+        }
+        return size;
+    }
+
+    protected abstract static class RecursiveObjectSize extends TruffleBoundaryNode {
+
+        protected abstract int executeInt(Object o);
+
+        @Child ObjectSize objectSize = ObjectSizeNodeGen.create();
+
+        @Specialization
+        protected int objectSize(Object o) {
+            return objectSize.executeInt(o);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c b/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c
index 0041d2830b859ef9634b0db37bbac70c32e7926b..72b60fd49b8e62b81b4ca4eff6362383c4d798ed 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c
+++ b/com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c
@@ -191,6 +191,8 @@ INLINE_FUN SEXP listAppend(SEXP s, SEXP t)
 }
 
 
+SEXP SET_TYPEOF_FASTR(SEXP x, int v);
+
 /* Language based list constructs.  These are identical to the list */
 /* constructs, but the results can be evaluated. */
 
@@ -199,8 +201,7 @@ INLINE_FUN SEXP listAppend(SEXP s, SEXP t)
 INLINE_FUN SEXP lcons(SEXP car, SEXP cdr)
 {
     SEXP e = cons(car, cdr);
-    e = SET_TYPEOF_FASTR(e, LANGSXP);
-    return e;
+    return SET_TYPEOF_FASTR(e, LANGSXP);
 }
 
 INLINE_FUN SEXP lang1(SEXP s)
diff --git a/com.oracle.truffle.r.native/fficall/src/common/localecharset_fastr.c b/com.oracle.truffle.r.native/fficall/src/common/localecharset_fastr.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba28eaf017e4356a9af4c30961a41c42f8e2c1cc
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/common/localecharset_fastr.c
@@ -0,0 +1,20 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995-2015, The R Core Team
+ * Copyright (c) 2003, The R Foundation
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+
+#include <Rinternals.h>
+#include <stdlib.h>
+
+const char *locale2charset(const char *locale)
+{
+	return "UTF-8";
+}
+
diff --git a/com.oracle.truffle.r.native/fficall/src/common/unimplemented.c b/com.oracle.truffle.r.native/fficall/src/common/unimplemented.c
index c03eda625456912a28ae407e33a0a614f56dc1b2..28dc2ccca5f9db279856d872988510eb0300b403 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/unimplemented.c
+++ b/com.oracle.truffle.r.native/fficall/src/common/unimplemented.c
@@ -75,12 +75,6 @@ addInputHandler(InputHandler *handlers, int fd, InputHandlerProc handler,
     return NULL;
 }
 
-const char *locale2charset(const char *locale)
-{
-	unimplemented("locale2charset");
-	return NULL;
-}
-
 void setup_RdotApp(void) {
 	unimplemented("setup_RdotApp");
 }
@@ -126,3 +120,32 @@ SEXP R_Unserialize(R_inpstream_t stream)
 	unimplemented("R_Unserialize");
 	return NULL;
 }
+
+SEXP R_getS4DataSlot(SEXP obj, SEXPTYPE type) {
+	unimplemented("R_getS4DataSlot");
+	return NULL;
+}
+
+void Rf_checkArityCall(SEXP a, SEXP b, SEXP c) {
+	unimplemented("Rf_checkArityCall");
+}
+
+SEXP NewEnvironment(SEXP a, SEXP b, SEXP c) {
+	unimplemented("NewEnvironment");
+	return NULL;
+}
+
+void* PRIMFUN(SEXP x) {
+	unimplemented("NewEnvironment");
+	return NULL;
+}
+
+SEXP coerceToSymbol(SEXP v) {
+	unimplemented("coerceToSymbol");
+}
+
+int IntegerFromString(SEXP a, int* b) {
+	unimplemented("IntegerFromString");
+	return 0;
+}
+
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Parse.c b/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
index 387a7b43cbe06349a4e5d9beb05c4bb9d4268b26..4727c2cba093be8d04f683e06f42b17eec0eed15 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -23,6 +23,22 @@
 #include <rffiutils.h>
 #include <R_ext/Parse.h>
 
-SEXP R_ParseVector(SEXP x, int y, ParseStatus *z, SEXP w) {
-	return unimplemented("R_ParseVector");
+static jmethodID parseMethodID;
+static jclass parseResultClass;
+static jfieldID parseStatusFieldID;
+static jfieldID parseExprFieldID;
+
+
+void init_parse(JNIEnv *env) {
+	parseMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ParseVector", "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;", 1);
+	parseResultClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper$ParseResult");
+	parseStatusFieldID = checkGetFieldID(env, parseResultClass, "parseStatus", "I", 0);
+	parseExprFieldID = checkGetFieldID(env, parseResultClass, "expr", "Ljava/lang/Object;", 0);
+}
+
+SEXP R_ParseVector(SEXP text, int n, ParseStatus *z, SEXP srcfile) {
+	JNIEnv *env = getEnv();
+	jobject result = (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, parseMethodID, text, n, srcfile);
+	*z = (*env)->GetIntField(env, result, parseStatusFieldID);
+    return (*env)->GetObjectField(env, result, parseExprFieldID);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/README.md b/com.oracle.truffle.r.native/fficall/src/jni/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..244e2df7a9e6bbaf3b3d85f7362af7707e179f04
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/jni/README.md
@@ -0,0 +1,12 @@
+# Notes on the JNI implementation
+
+## JNI References
+
+Java object values are passed to native code using JNI local references that are valid for the duration of the call. The reference protects the object from garbage collection. Evidently if native code holds on to a local reference by storing it in a native variable,
+that object might be collected, possibly causing incorrect behavior (at best) later in the execution. It is possible to convert a local reference to a global reference that preserves the object across multiple JNI calls but this risks preventing objects from being collected. The global variables defined in the R FFI, e.g. R_NilValue are necessarily handled as global references. However, by default, other values are left as local references, although this can be changed by setting the variable alwaysUseGlobal in rffiutils.c to a non-zero value.
+
+## Vector Content Copying
+
+The R FFI provides access to vector contents as raw C pointers, e.g., int *. This requires the use of the JNI functions to access/copy the underlying data. In addition it requires  that multiple calls on the same SEXP always return the same raw pointer.
+Similar to the discussion on JNI references, the raw data is released at the end of the call. There is currently no provision to retain this data across multiple JNI calls.
+
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rdynload_fastr.c b/com.oracle.truffle.r.native/fficall/src/jni/Rdynload_fastr.c
index 2983383669e0e48e612c4ae8793ffe1aeb54a755..f0b05fc5733fe75249d9b14e5aaf0f1a35465176 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rdynload_fastr.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rdynload_fastr.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,23 +17,29 @@
 static jclass DLLClass;
 static jclass JNI_PkgInitClass;
 static jclass DotSymbolClass;
+static jclass RegisteredNativeSymbolClass;
 
 static jmethodID registerRoutinesID;
 static jmethodID registerCCallableID;
 static jmethodID useDynamicSymbolsID;
 static jmethodID forceSymbolsID;
 static jmethodID setDotSymbolValuesID;
+static jmethodID getEmbeddingDllInfoID;
+static jmethodID findSymbolID;
 
 void init_dynload(JNIEnv *env) {
     DLLClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/DLL");
     JNI_PkgInitClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jnr/JNI_PkgInit");
     DotSymbolClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/DLL$DotSymbol");
+    RegisteredNativeSymbolClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/DLL$RegisteredNativeSymbol");
 
     registerRoutinesID = checkGetMethodID(env, JNI_PkgInitClass, "registerRoutines", "(Lcom/oracle/truffle/r/runtime/ffi/DLL$DLLInfo;IIJ)V", 1);
     registerCCallableID = checkGetMethodID(env, JNI_PkgInitClass, "registerCCallable", "(Ljava/lang/String;Ljava/lang/String;J)V", 1);
     useDynamicSymbolsID = checkGetMethodID(env, JNI_PkgInitClass, "useDynamicSymbols", "(Lcom/oracle/truffle/r/runtime/ffi/DLL$DLLInfo;I)I", 1);
     forceSymbolsID = checkGetMethodID(env, JNI_PkgInitClass, "forceSymbols", "(Lcom/oracle/truffle/r/runtime/ffi/DLL$DLLInfo;I)I", 1);
     setDotSymbolValuesID = checkGetMethodID(env, JNI_PkgInitClass, "setDotSymbolValues", "(Ljava/lang/String;JI)Lcom/oracle/truffle/r/runtime/ffi/DLL$DotSymbol;", 1);
+    getEmbeddingDllInfoID = checkGetMethodID(env, JNI_PkgInitClass, "getEmbeddingDllInfo", "()Lcom/oracle/truffle/r/runtime/ffi/DLL$DLLInfo;", 1);
+    findSymbolID = checkGetMethodID(env, JNI_PkgInitClass, "findSymbol", "(Ljava/lang/String;Ljava/lang/String;Lcom/oracle/truffle/r/runtime/ffi/DLL$RegisteredNativeSymbol;)I", 1);
 }
 
 // Must match ordinal value for DLL.NativeSymbolType
@@ -141,3 +147,8 @@ DL_FUNC R_FindSymbol(char const *name, char const *pkg,
     unimplemented("R_FindSymbol");
     return NULL;
 }
+
+DllInfo *R_getEmbeddingDllInfo(void) {
+	JNIEnv *thisenv = getEnv();
+	return (*thisenv)->CallStaticObjectMethod(thisenv, JNI_PkgInitClass, getEmbeddingDllInfoID);
+}
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
new file mode 100644
index 0000000000000000000000000000000000000000..61431ad1d6d0b6c2717a6d7d17d8babc84c26456
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
@@ -0,0 +1,629 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995-2015, The R Core Team
+ * Copyright (c) 2003, The R Foundation
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+#include <dlfcn.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <rffiutils.h>
+#define R_INTERFACE_PTRS
+#include <Rinterface.h>
+#include <R_ext/RStartup.h>
+
+extern char **environ;
+
+static JavaVM *javaVM;
+static jobject engine;
+static int initialized = 0;
+static char *java_home;
+
+static jclass rembeddedClass;
+static jclass rStartParamsClass;
+static jclass rInterfaceCallbacksClass;
+
+int R_running_as_main_program;
+int R_SignalHandlers;
+FILE * R_Consolefile;
+FILE * R_Outputfile;
+int R_DirtyImage; // TODO update this
+void *R_GlobalContext; // TODO what?
+SA_TYPE SaveAction; // ??
+
+typedef jint (JNICALL *JNI_CreateJavaVMFunc)
+	      (JavaVM **pvm, void **penv, void *args);
+
+
+static void *dlopen_jvmlib(char *libpath) {
+	void *handle = dlopen(libpath, RTLD_GLOBAL | RTLD_NOW);
+	if (handle == NULL) {
+		fprintf(stderr, "Rf_initialize_R: cannot dlopen %s: %s\n", libpath, dlerror());
+		exit(1);
+	}
+	return handle;
+}
+
+// separate vm args from user args
+static int process_vmargs(int argc, char *argv[], char *vmargv[], char *uargv[]) {
+	int vcount = 0;
+	int ucount = 0;
+	for (int i = 0; i < argc; i++) {
+		char *arg = argv[i];
+		if ((arg[0] == '-' && arg[1] == 'X') || (arg[0] == '-' && arg[1] == 'D')) {
+			vmargv[vcount++] = arg;
+		} else {
+			uargv[ucount++] = arg;
+		}
+	}
+	return vcount;
+}
+
+static char **update_environ_with_java_home(void);
+static void print_environ(char **env);
+static char *get_classpath(char *r_home);
+
+# define JMP_BUF sigjmp_buf
+
+int Rf_initialize_R(int argc, char *argv[]) {
+	if (initialized) {
+		fprintf(stderr, "%s", "R is already initialized\n");
+		exit(1);
+	}
+	// print_environ(environ);
+	char *r_home = getenv("R_HOME");
+	if (r_home == NULL) {
+		fprintf(stderr, "R_HOME must be set\n");
+		exit(1);
+	}
+	struct utsname utsname;
+	uname(&utsname);
+	char jvmlib_path[256];
+	java_home = getenv("JAVA_HOME");
+	if (java_home == NULL) {
+		if (strcmp(utsname.sysname, "Linux") == 0) {
+			char *jvmdir = "/usr/java/latest";
+			struct stat statbuf;
+			if (stat(jvmdir, &statbuf) == 0) {
+				java_home = jvmdir;
+			}
+		} else if (strcmp(utsname.sysname, "Darwin") == 0) {
+			char *jvmdir = "/Library/Java/JavaVirtualMachines/jdk.latest";
+			struct stat statbuf;
+			if (stat(jvmdir, &statbuf) == 0) {
+				java_home = (char*)malloc(strlen(jvmdir) + 32);
+				strcpy(java_home, jvmdir);
+				strcat(java_home, "/Contents/Home");
+			}
+		}
+		if (java_home == NULL) {
+			fprintf(stderr, "Rf_initialize_R: can't find a JAVA_HOME\n");
+			exit(1);
+		}
+	}
+	strcpy(jvmlib_path, java_home);
+	if (strcmp(utsname.sysname, "Linux") == 0) {
+		strcat(jvmlib_path, "/jre/lib/amd64/server/libjvm.so");
+	} else if (strcmp(utsname.sysname, "Darwin") == 0) {
+		strcat(jvmlib_path, "/jre/lib/server/libjvm.dylib");
+        // Must also load libjli to avoid going through framework
+		// and failing to find our JAVA_HOME runtime
+		char jlilib_path[256];
+		strcpy(jlilib_path, java_home);
+		strcat(jlilib_path, "/jre/lib/jli/libjli.dylib");
+		dlopen_jvmlib(jlilib_path);
+	} else {
+		fprintf(stderr, "unsupported OS: %s\n", utsname.sysname);
+		exit(1);
+	}
+	void *vm_handle = dlopen_jvmlib(jvmlib_path);
+	JNI_CreateJavaVMFunc createJavaVMFunc = (JNI_CreateJavaVMFunc) dlsym(vm_handle, "JNI_CreateJavaVM");
+	if (createJavaVMFunc == NULL) {
+		fprintf(stderr, "Rf_initialize_R: cannot find JNI_CreateJavaVM\n");
+		exit(1);
+	}
+
+	char *vm_cp = get_classpath(r_home);
+	//printf("cp %s\n", vm_cp);
+
+	char **vmargs = malloc(argc * sizeof(char*));
+	char **uargs = malloc(argc * sizeof(char*));
+	int vmargc = process_vmargs(argc, argv, vmargs, uargs);
+	argc -= vmargc;
+	argv = uargs;
+	JavaVMOption vm_options[1 + vmargc];
+
+	vm_options[0].optionString = vm_cp;
+	for (int i = 0; i < vmargc; i++) {
+		vm_options[i + 1].optionString = vmargs[i];
+	}
+
+	JavaVMInitArgs vm_args;
+	vm_args.version = JNI_VERSION_1_8;
+	vm_args.nOptions = 1 + vmargc;
+	vm_args.options = vm_options;
+	vm_args.ignoreUnrecognized = JNI_TRUE;
+
+	JNIEnv *jniEnv;
+	jint flag = (*createJavaVMFunc)(&javaVM, (void**)
+			&jniEnv, &vm_args);
+	if (flag == JNI_ERR) {
+		fprintf(stderr, "Rf_initEmbeddedR: error creating Java VM, exiting...\n");
+		return 1;
+	}
+
+	setEmbedded();
+	setEnv(jniEnv);
+	rInterfaceCallbacksClass = checkFindClass(jniEnv, "com/oracle/truffle/r/runtime/RInterfaceCallbacks");
+	rembeddedClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/REmbedded");
+	rStartParamsClass = checkFindClass(jniEnv, "com/oracle/truffle/r/runtime/RStartParams");
+	jclass stringClass = checkFindClass(jniEnv, "java/lang/String");
+	jmethodID initializeMethod = checkGetMethodID(jniEnv, rembeddedClass, "initializeR",
+			"([Ljava/lang/String;)Lcom/oracle/truffle/api/vm/PolyglotEngine;", 1);
+	jobjectArray argsArray = (*jniEnv)->NewObjectArray(jniEnv, argc, stringClass, NULL);
+	for (int i = 0; i < argc; i++) {
+		jstring arg = (*jniEnv)->NewStringUTF(jniEnv, argv[i]);
+		(*jniEnv)->SetObjectArrayElement(jniEnv, argsArray, i, arg);
+	}
+	// Can't TRACE this upcall as system not initialized
+	engine = checkRef(jniEnv, (*jniEnv)->CallStaticObjectMethod(jniEnv, rembeddedClass, initializeMethod, argsArray));
+	initialized++;
+	return 0;
+}
+
+char *R_HomeDir(void) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID R_HomeDirMethodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_HomeDir", "()Ljava/lang/String;", 1);
+	jstring homeDir = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, R_HomeDirMethodID);
+	const char *homeDirChars = stringToChars(jniEnv, homeDir);
+	return (char *)homeDirChars;
+}
+
+void R_SaveGlobalEnvToFile(const char *f) {
+	unimplemented("R_SaveGlobalEnvToFile");
+}
+
+void R_Suicide(const char *s) { ptr_R_Suicide(s); }
+
+
+void R_DefParams(Rstart rs) {
+    // These are the GnuR defaults and correspond to the settings in RStartParams
+	// None of the size params make any sense for FastR
+    rs->R_Quiet = FALSE;
+    rs->R_Slave = FALSE;
+    rs->R_Interactive = TRUE;
+    rs->R_Verbose = FALSE;
+    rs->RestoreAction = SA_RESTORE;
+    rs->SaveAction = SA_SAVEASK;
+    rs->LoadSiteFile = TRUE;
+    rs->LoadInitFile = TRUE;
+    rs->DebugInitFile = FALSE;
+//    rs->vsize = R_VSIZE;
+//    rs->nsize = R_NSIZE;
+//    rs->max_vsize = R_SIZE_T_MAX;
+//    rs->max_nsize = R_SIZE_T_MAX;
+//    rs->ppsize = R_PPSSIZE;
+    rs->NoRenviron = FALSE;
+//    R_SizeFromEnv(Rp);
+}
+
+void R_SetParams(Rstart rs) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID setParamsMethodID = checkGetMethodID(jniEnv, rStartParamsClass, "setParams", "(ZZZZZZZIIZ)V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, rStartParamsClass, setParamsMethodID, rs->R_Quiet, rs->R_Slave, rs->R_Interactive,
+			rs->R_Verbose, rs->LoadSiteFile, rs->LoadInitFile, rs->DebugInitFile,
+			rs->RestoreAction, rs->SaveAction, rs->NoRenviron);
+}
+
+void R_SizeFromEnv(Rstart rs) {
+	unimplemented("R_SizeFromEnv");
+}
+
+void R_common_command_line(int *a, char **b, Rstart rs) {
+	unimplemented("R_common_command_line");
+}
+
+void R_set_command_line_arguments(int argc, char **argv) {
+	unimplemented("R_set_command_line_arguments");
+}
+
+
+int Rf_initEmbeddedR(int argc, char *argv[]) {
+	Rf_initialize_R(argc, argv);
+	R_Interactive = TRUE;
+    setup_Rmainloop();
+    return 1;
+}
+
+void Rf_endEmbeddedR(int fatal) {
+	(*javaVM)->DestroyJavaVM(javaVM);
+	//TODO fatal
+}
+
+static void setupOverrides(void);
+
+void setup_Rmainloop(void) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID setupMethod = checkGetMethodID(jniEnv, rembeddedClass, "setupRmainloop", "(Lcom/oracle/truffle/api/vm/PolyglotEngine;)V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, rembeddedClass, setupMethod, engine);
+}
+
+void run_Rmainloop(void) {
+	JNIEnv *jniEnv = getEnv();
+	setupOverrides();
+	jmethodID mainloopMethod = checkGetMethodID(jniEnv, rembeddedClass, "runRmainloop", "(Lcom/oracle/truffle/api/vm/PolyglotEngine;)V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, rembeddedClass, mainloopMethod, engine);
+}
+
+void Rf_mainloop(void) {
+	setup_Rmainloop();
+	run_Rmainloop();
+}
+
+// functions that can be assigned by an embedded client to change behavior
+
+void uR_Suicide(const char *x) {
+	JNIEnv *jniEnv = getEnv();
+	jstring msg = (*jniEnv)->NewStringUTF(jniEnv, x);
+	jmethodID suicideMethod = checkGetMethodID(jniEnv, rembeddedClass, "R_Suicide", "(Ljava/lang/String;)V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, rembeddedClass, suicideMethod, msg);
+}
+
+void uR_ShowMessage(const char *x) {
+	unimplemented("R_ShowMessage");
+}
+
+int uR_ReadConsole(const char *a, unsigned char *b, int c, int d) {
+	return (int) unimplemented("R_ReadConsole");
+}
+
+void uR_WriteConsole(const char *x, int y) {
+	unimplemented("R_WriteConsole");
+}
+
+void uR_WriteConsoleEx(const char *x, int y, int z) {
+	unimplemented("R_WriteConsole");
+}
+
+void uR_ResetConsole(void) {
+	unimplemented("R_ResetConsole");
+}
+
+void uR_FlushConsole(void) {
+	unimplemented("R_FlushConsole");
+}
+
+void uR_ClearerrConsole(void) {
+	unimplemented("R_ClearerrConsole");
+}
+
+void uR_Busy(int x) {
+	unimplemented("R_Busy");
+}
+
+void uR_CleanUp(SA_TYPE x, int y, int z) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_CleanUp", "(III)V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, CallRFFIHelperClass, methodID, x, y, z);
+}
+
+int uR_ShowFiles(int a, const char **b, const char **c,
+	       const char *d, Rboolean e, const char *f) {
+	return (int) unimplemented("R_ShowFiles");
+}
+
+int uR_ChooseFile(int a, char *b, int c) {
+	return (int) unimplemented("R_ChooseFile");
+}
+
+int uR_EditFile(const char *a) {
+	return (int) unimplemented("R_EditFile");
+}
+
+void uR_loadhistory(SEXP a, SEXP b, SEXP c, SEXP d) {
+	unimplemented("uR_loadhistory");
+}
+
+void uR_savehistory(SEXP a, SEXP b, SEXP c, SEXP d) {
+	unimplemented("R_savehistory");
+}
+
+void uR_addhistory(SEXP a, SEXP b, SEXP c, SEXP d) {
+	unimplemented("R_addhistory");
+}
+
+int  uR_EditFiles(int a, const char **b, const char **c, const char *d) {
+	return (int)unimplemented("");
+}
+
+SEXP udo_selectlist(SEXP a, SEXP b, SEXP c, SEXP d) {
+	return unimplemented("R_EditFiles");
+}
+
+SEXP udo_dataentry(SEXP a, SEXP b, SEXP c, SEXP d) {
+	return unimplemented("do_dataentry");
+}
+
+SEXP udo_dataviewer(SEXP a, SEXP b, SEXP c, SEXP d) {
+	return unimplemented("do_dataviewer");
+}
+
+void uR_ProcessEvents(void) {
+	unimplemented("R_ProcessEvents");
+}
+
+
+void (*ptr_R_Suicide)(const char *) = uR_Suicide;
+void (*ptr_R_ShowMessage)(const char *) = uR_ShowMessage;
+int  (*ptr_R_ReadConsole)(const char *, unsigned char *, int, int) = uR_ReadConsole;
+void (*ptr_R_WriteConsole)(const char *, int) = uR_WriteConsole;
+void (*ptr_R_WriteConsoleEx)(const char *, int, int) = uR_WriteConsoleEx;
+void (*ptr_R_ResetConsole)(void) = uR_ResetConsole;
+void (*ptr_R_FlushConsole)(void) = uR_FlushConsole;
+void (*ptr_R_ClearerrConsole)(void) = uR_ClearerrConsole;
+void (*ptr_R_Busy)(int) = uR_Busy;
+void (*ptr_R_CleanUp)(SA_TYPE, int, int) = uR_CleanUp;
+int  (*ptr_R_ShowFiles)(int, const char **, const char **,
+			       const char *, Rboolean, const char *) = uR_ShowFiles;
+int  (*ptr_R_ChooseFile)(int, char *, int) = uR_ChooseFile;
+int  (*ptr_R_EditFile)(const char *) = uR_EditFile;
+void (*ptr_R_loadhistory)(SEXP, SEXP, SEXP, SEXP) = uR_loadhistory;
+void (*ptr_R_savehistory)(SEXP, SEXP, SEXP, SEXP) = uR_savehistory;
+void (*ptr_R_addhistory)(SEXP, SEXP, SEXP, SEXP) = uR_addhistory;
+
+int  (*ptr_R_EditFiles)(int, const char **, const char **, const char *) = uR_EditFiles;
+
+SEXP (*ptr_do_selectlist)(SEXP, SEXP, SEXP, SEXP) = udo_selectlist;
+SEXP (*ptr_do_dataentry)(SEXP, SEXP, SEXP, SEXP) = udo_dataentry;
+SEXP (*ptr_do_dataviewer)(SEXP, SEXP, SEXP, SEXP) = udo_dataviewer;
+void (*ptr_R_ProcessEvents)() = uR_ProcessEvents;
+
+void setupOverrides(void) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID ovrMethodID = checkGetMethodID(jniEnv, rInterfaceCallbacksClass, "override", "(Ljava/lang/String;)V", 1);
+	jstring name;
+	if (ptr_R_Suicide != uR_Suicide) {
+		name = (*jniEnv)->NewStringUTF(jniEnv, "R_Suicide");
+		(*jniEnv)->CallStaticVoidMethod(jniEnv, rInterfaceCallbacksClass, ovrMethodID, name);
+	}
+	if (*ptr_R_CleanUp != uR_CleanUp) {
+		name = (*jniEnv)->NewStringUTF(jniEnv, "R_CleanUp");
+		(*jniEnv)->CallStaticVoidMethod(jniEnv, rInterfaceCallbacksClass, ovrMethodID, name);
+	}
+	if (*ptr_R_ReadConsole != uR_ReadConsole) {
+		name = (*jniEnv)->NewStringUTF(jniEnv, "R_ReadConsole");
+		(*jniEnv)->CallStaticVoidMethod(jniEnv, rInterfaceCallbacksClass, ovrMethodID, name);
+	}
+	if (*ptr_R_WriteConsole != uR_WriteConsole) {
+		name = (*jniEnv)->NewStringUTF(jniEnv, "R_WriteConsole");
+		(*jniEnv)->CallStaticVoidMethod(jniEnv, rInterfaceCallbacksClass, ovrMethodID, name);
+	}
+}
+
+static void REmbed_nativeWriteConsole(JNIEnv *jniEnv, jclass c, jstring string, int otype) {
+	int len = (*jniEnv)->GetStringUTFLength(jniEnv, string);
+	const char *cbuf =  (*jniEnv)->GetStringUTFChars(jniEnv, string, NULL);
+	if (ptr_R_WriteConsole == NULL) {
+		(*ptr_R_WriteConsoleEx)(cbuf, len, otype);
+	} else {
+	    (*ptr_R_WriteConsole)(cbuf, len);
+	}
+	(*jniEnv)->ReleaseStringUTFChars(jniEnv, string, cbuf);
+}
+
+JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeWriteConsole(JNIEnv *jniEnv, jclass c, jstring string) {
+	REmbed_nativeWriteConsole(jniEnv, c, string, 0);
+}
+
+JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeWriteErrConsole(JNIEnv *jniEnv, jclass c, jstring string) {
+	REmbed_nativeWriteConsole(jniEnv, c, string, 1);
+}
+
+JNIEXPORT jstring JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeReadConsole(JNIEnv *jniEnv, jclass c, jstring prompt) {
+	const char *cprompt =  (*jniEnv)->GetStringUTFChars(jniEnv, prompt, NULL);
+	unsigned char cbuf[1024];
+	int n = (*ptr_R_ReadConsole)(cprompt, cbuf, 1024, 0);
+	jstring result;
+	result = (*jniEnv)->NewStringUTF(jniEnv, (const char *)cbuf);
+	(*jniEnv)->ReleaseStringUTFChars(jniEnv, prompt, cprompt);
+	return result;
+}
+
+JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeCleanUp(JNIEnv *jniEnv, jclass c, jint x, jint y, jint z) {
+	(*ptr_R_CleanUp)(x, y, z);
+}
+
+JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeSuicide(JNIEnv *jniEnv, jclass c, jstring string) {
+	const char *cbuf =  (*jniEnv)->GetStringUTFChars(jniEnv, string, NULL);
+	(*ptr_R_Suicide)(cbuf);
+}
+
+void uR_PolledEvents(void) {
+	unimplemented("R_PolledEvents");
+}
+
+void (* R_PolledEvents)(void) = uR_PolledEvents;
+
+void Rf_jump_to_toplevel() {
+	unimplemented("Rf_jump_to_toplevel");
+}
+
+#include <R_ext/eventloop.h>
+
+fd_set *R_checkActivity(int usec, int ignore_stdin) {
+	return (fd_set*) unimplemented("R_checkActivity");
+}
+
+void R_runHandlers(InputHandler *handlers, fd_set *mask) {
+	unimplemented("R_runHandlers");
+}
+
+int R_wait_usec;
+
+#include <unistd.h>
+#include <errno.h>
+
+static void perror_exit(char *msg) {
+	perror(msg);
+	exit(1);
+}
+
+// support for getting the correct classpath for the VM
+// We use $R_HOME/bin/execRextras/Rclasspath to do this to emulate what happens
+// during normal execution
+static char *get_classpath(char *r_home) {
+	char **env = update_environ_with_java_home();
+	//print_environ(env);
+	int pipefd[2];
+	if (pipe(pipefd) == -1) {
+		perror_exit("pipe");
+	}
+	pid_t pid = fork();
+	if (pid == -1) {
+		perror("fork");
+	}
+	if (pid == 0) {
+		// child
+		char path[1024];
+		strcpy(path, r_home);
+		strcat(path, "/bin/execRextras/Rclasspath");
+		while ((dup2(pipefd[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
+		close(pipefd[1]);
+		close(pipefd[0]);
+		int rc = execle(path, path, (char *)NULL, env);
+		if (rc == -1) {
+			perror_exit("exec");
+		}
+		return NULL;
+	} else {
+		// parent
+		const char *cpdef = "-Djava.class.path=";
+		char *buf = malloc(4096);
+		strcpy(buf, cpdef);
+		char *bufptr = buf + strlen(cpdef);
+		int max = 4096 - strlen(cpdef);
+		close(pipefd[1]);
+		while (1) {
+			int count = read(pipefd[0], bufptr, max);
+			if (count == -1) {
+				if (errno == EINTR) {
+					continue;
+				} else {
+					perror_exit("read");
+				}
+			} else if (count == 0) {
+			    // scrub any newline
+			    bufptr--;
+			    if (*bufptr != '\n') {
+			        bufptr++;
+			    }
+				*bufptr = 0;
+				break;
+			} else {
+				bufptr += count;
+				max -= count;
+			}
+		}
+		close(pipefd[0]);
+		wait(NULL);
+		return buf;
+	}
+}
+
+// debugging
+static void print_environ(char **env) {
+	fprintf(stdout, "## Environment variables at %p\n", env);
+	char **e = env;
+	while (*e != NULL) {
+		fprintf(stdout, "%s\n", *e);
+		e++;
+	}
+}
+
+static char **update_environ(char *def) {
+	int count = 0;
+	char **e = environ;
+	while (*e != NULL) {
+		e++;
+		count++;
+	}
+	char **new_env = malloc(sizeof(char *) * (count + 2));
+	e = environ;
+	char **ne = new_env;
+	while (*e != NULL) {
+		*ne++ = *e++;
+	}
+	*ne++ = def;
+	*ne = (char*) NULL;
+	return new_env;
+}
+
+static char **update_environ_with_java_home(void) {
+	char **e = environ;
+	while (*e != NULL) {
+		if (strstr(*e, "JAVA_HOME=")) {
+			return environ;
+		}
+		e++;
+	}
+	char *java_home_env = malloc(strlen(java_home) + 10);
+	strcpy(java_home_env, "JAVA_HOME=");
+	strcat(java_home_env, java_home);
+	return update_environ(java_home_env);
+}
+
+CTXT R_getGlobalFunctionContext() {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getGlobalFunctionContext", "()Ljava/lang/Object;", 1);
+    CTXT result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID);
+    result = checkRef(jniEnv, result);
+    return result == R_NilValue ? NULL : result;
+}
+
+CTXT R_getParentFunctionContext(CTXT c) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getParentFunctionContext", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+    CTXT result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, c);
+    result = checkRef(jniEnv, result);
+    return result == R_NilValue ? NULL : result;
+}
+
+SEXP R_getContextEnv(CTXT context) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextEnv", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+    return checkRef(jniEnv, result);
+}
+
+SEXP R_getContextFun(CTXT context) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextFun", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+    return checkRef(jniEnv, result);
+}
+
+SEXP R_getContextCall(CTXT context) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextCall", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+    return checkRef(jniEnv, result);
+}
+
+SEXP R_getContextSrcRef(CTXT context) {
+    JNIEnv *jniEnv = getEnv();
+    jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextSrcRef", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+    result = checkRef(jniEnv, result);
+    return result == R_NilValue ? NULL : result;
+}
+
+int R_insideBrowser() {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_insideBrowser", "()I", 1);
+    return (*jniEnv)->CallStaticIntMethod(jniEnv, CallRFFIHelperClass, methodID);
+}
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
index 533787d5d3e80c48fa6efcbdf35c4414e0f72161..14227cbd329b3acd95354e84d88609a379ecbaee 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -25,6 +25,11 @@
 
 // Most everything in RInternals.h
 
+// N.B. When implementing a new method that returns a SEXP, you MUST
+// explicitly (or implicitly) return via "checkRef(thisenv, result)"
+// to ensure that a global JNI handle is created (if necessary) and returned,
+// otherwise a GC might reclaim the result.
+
 static jmethodID Rf_ScalarIntegerMethodID;
 static jmethodID Rf_ScalarDoubleMethodID;
 static jmethodID Rf_ScalarStringMethodID;
@@ -40,6 +45,7 @@ static jmethodID Rf_findfunMethodID;
 static jmethodID Rf_defineVarMethodID;
 static jmethodID Rf_findVarMethodID;
 static jmethodID Rf_findVarInFrameMethodID;
+static jmethodID Rf_findVarInFrame3MethodID;
 static jmethodID Rf_getAttribMethodID;
 static jmethodID Rf_setAttribMethodID;
 static jmethodID Rf_isStringMethodID;
@@ -52,6 +58,7 @@ static jmethodID Rf_rPsortMethodID;
 static jmethodID Rf_iPsortMethodID;
 static jmethodID RprintfMethodID;
 static jmethodID R_FindNamespaceMethodID;
+static jmethodID R_BindingIsLockedID;
 static jmethodID Rf_GetOption1MethodID;
 static jmethodID Rf_gsetVarMethodID;
 static jmethodID Rf_inheritsMethodID;
@@ -65,12 +72,14 @@ static jmethodID CDDR_MethodID;
 static jmethodID SET_TAG_MethodID;
 static jmethodID SETCAR_MethodID;
 static jmethodID SETCDR_MethodID;
+static jmethodID SYMVALUE_MethodID;
+static jmethodID SET_SYMVALUE_MethodID;
 static jmethodID SET_STRING_ELT_MethodID;
 static jmethodID SET_VECTOR_ELT_MethodID;
-static jmethodID RAW_MethodID;
-static jmethodID INTEGER_MethodID;
-static jmethodID REAL_MethodID;
-static jmethodID LOGICAL_MethodID;
+jmethodID RAW_MethodID;
+jmethodID INTEGER_MethodID;
+jmethodID REAL_MethodID;
+jmethodID LOGICAL_MethodID;
 static jmethodID STRING_ELT_MethodID;
 static jmethodID VECTOR_ELT_MethodID;
 static jmethodID LENGTH_MethodID;
@@ -88,8 +97,21 @@ static jmethodID OBJECT_MethodID;
 static jmethodID DUPLICATE_ATTRIB_MethodID;
 static jmethodID isS4ObjectMethodID;
 static jmethodID logObject_MethodID;
+static jmethodID R_tryEvalMethodID;
+static jmethodID RDEBUGMethodID;
+static jmethodID SET_RDEBUGMethodID;
+static jmethodID RSTEPMethodID;
+static jmethodID SET_RSTEPMethodID;
+static jmethodID ENCLOSMethodID;
+static jmethodID PRVALUEMethodID;
+static jmethodID R_lsInternal3MethodID;
 static jmethodID R_do_MAKE_CLASS_MethodID;
 
+static jclass rErrorHandlingClass;
+static jclass handlerStacksClass;
+static jmethodID resetAndGetHandlerStacksMethodID;
+static jmethodID restoreHandlerStacksMethodID;
+
 static jclass RExternalPtrClass;
 static jmethodID createExternalPtrMethodID;
 static jmethodID externalPtrGetAddrMethodID;
@@ -104,7 +126,7 @@ static jmethodID Rf_copyListMatrixMethodID;
 static jmethodID Rf_copyMatrixMethodID;
 
 static jclass CharSXPWrapperClass;
-static jfieldID CharXSPWrapperContentsFieldID;
+static jfieldID CharSXPWrapperContentsFieldID;
 
 void init_internals(JNIEnv *env) {
 	Rf_ScalarIntegerMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_ScalarInteger", "(I)Lcom/oracle/truffle/r/runtime/data/RIntVector;", 1);
@@ -117,6 +139,7 @@ void init_internals(JNIEnv *env) {
 	Rf_defineVarMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_defineVar", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 1);
 	Rf_findVarMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_findVar", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
 	Rf_findVarInFrameMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_findVarInFrame", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	Rf_findVarInFrame3MethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_findVarInFrame3", "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/Object;", 1);
 	Rf_getAttribMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_getAttrib", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
 	Rf_setAttribMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_setAttrib", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 1);
 	Rf_isStringMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_isString", "(Ljava/lang/Object;)I", 1);
@@ -133,6 +156,7 @@ void init_internals(JNIEnv *env) {
 	RprintfMethodID = checkGetMethodID(env, CallRFFIHelperClass, "printf", "(Ljava/lang/String;)V", 1);
 	R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_do_MAKE_CLASS", "(Ljava/lang/String;)Ljava/lang/Object;", 1);
 	R_FindNamespaceMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_FindNamespace", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	R_BindingIsLockedID = checkGetMethodID(env, CallRFFIHelperClass, "R_BindingIsLocked", "(Ljava/lang/Object;Ljava/lang/Object;)I", 1);
 	Rf_GetOption1MethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_GetOption1", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
 	Rf_gsetVarMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_gsetVar", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 1);
 	Rf_inheritsMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_inherits", "(Ljava/lang/Object;Ljava/lang/String;)I", 1);
@@ -148,6 +172,8 @@ void init_internals(JNIEnv *env) {
 	SET_TAG_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_TAG", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
 	SETCAR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SETCAR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
 	SETCDR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SETCDR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	SYMVALUE_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SYMVALUE", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	SET_SYMVALUE_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_SYMVALUE", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
 	SET_STRING_ELT_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_STRING_ELT", "(Ljava/lang/Object;ILjava/lang/Object;)V", 1);
 	SET_VECTOR_ELT_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_VECTOR_ELT", "(Ljava/lang/Object;ILjava/lang/Object;)V", 1);
 	RAW_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "RAW", "(Ljava/lang/Object;)[B", 1);
@@ -170,6 +196,19 @@ void init_internals(JNIEnv *env) {
 	DUPLICATE_ATTRIB_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "DUPLICATE_ATTRIB", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
 	isS4ObjectMethodID = checkGetMethodID(env, CallRFFIHelperClass, "isS4Object", "(Ljava/lang/Object;)I", 1);
 	logObject_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "logObject", "(Ljava/lang/Object;)V", 1);
+	R_tryEvalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_tryEval", "(Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;", 1);
+	RDEBUGMethodID = checkGetMethodID(env, CallRFFIHelperClass, "RDEBUG", "(Ljava/lang/Object;)I", 1);
+	SET_RDEBUGMethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_RDEBUG", "(Ljava/lang/Object;I)V", 1);
+	RSTEPMethodID = checkGetMethodID(env, CallRFFIHelperClass, "RSTEP", "(Ljava/lang/Object;)I", 1);
+	SET_RSTEPMethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_RSTEP", "(Ljava/lang/Object;I)V", 1);
+	ENCLOSMethodID = checkGetMethodID(env, CallRFFIHelperClass, "ENCLOS", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	PRVALUEMethodID = checkGetMethodID(env, CallRFFIHelperClass, "PRVALUE", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	R_lsInternal3MethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_lsInternal3", "(Ljava/lang/Object;II)Ljava/lang/Object;", 1);
+
+	rErrorHandlingClass = checkFindClass(env, "com/oracle/truffle/r/runtime/RErrorHandling");
+	handlerStacksClass = checkFindClass(env, "com/oracle/truffle/r/runtime/RErrorHandling$HandlerStacks");
+	resetAndGetHandlerStacksMethodID = checkGetMethodID(env, rErrorHandlingClass, "resetAndGetHandlerStacks", "()Lcom/oracle/truffle/r/runtime/RErrorHandling$HandlerStacks;", 1);
+	restoreHandlerStacksMethodID = checkGetMethodID(env, rErrorHandlingClass, "restoreHandlerStacks", "(Lcom/oracle/truffle/r/runtime/RErrorHandling$HandlerStacks;)V", 1);
 
 	RExternalPtrClass = checkFindClass(env, "com/oracle/truffle/r/runtime/data/RExternalPtr");
 	createExternalPtrMethodID = checkGetMethodID(env, RDataFactoryClass, "createExternalPtr", "(JLjava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 1);
@@ -181,7 +220,7 @@ void init_internals(JNIEnv *env) {
 	externalPtrSetProtMethodID = checkGetMethodID(env, RExternalPtrClass, "setProt", "(Ljava/lang/Object;)V", 0);
 
 	CharSXPWrapperClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper$CharSXPWrapper");
-	CharXSPWrapperContentsFieldID = checkGetFieldID(env, CharSXPWrapperClass, "contents", "Ljava/lang/String;", 0);
+	CharSXPWrapperContentsFieldID = checkGetFieldID(env, CharSXPWrapperClass, "contents", "Ljava/lang/String;", 0);
 
     R_computeIdenticalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_computeIdentical", "(Ljava/lang/Object;Ljava/lang/Object;I)I", 1);
     Rf_copyListMatrixMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_copyListMatrix", "(Ljava/lang/Object;Ljava/lang/Object;I)V", 1);
@@ -197,11 +236,11 @@ static jstring stringFromCharSXP(JNIEnv *thisenv, SEXP charsxp) {
 	    fatalError("only CharSXPWrapper expected in stringFromCharSXP");
 	}
 #endif
-	return (*thisenv)->GetObjectField(thisenv, charsxp, CharXSPWrapperContentsFieldID);
+	return (*thisenv)->GetObjectField(thisenv, charsxp, CharSXPWrapperContentsFieldID);
 }
 
 SEXP Rf_ScalarInteger(int value) {
-	TRACE("%s(%d)\n", value);
+	TRACE(TARGp, value);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ScalarIntegerMethodID, value);
     return checkRef(thisenv, result);
@@ -232,14 +271,14 @@ int fastr_pcre_exec(void * code, void *extra,  char* subject, int subjectLength,
 }
 
 SEXP Rf_ScalarString(SEXP value) {
-	TRACE(TARG1, value);
+	TRACE(TARGp, value);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ScalarStringMethodID, value);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_ScalarLogical(int value) {
-	TRACE(TARG1, value);
+	TRACE(TARGp, value);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ScalarLogicalMethodID, value);
     return checkRef(thisenv, result);
@@ -247,17 +286,17 @@ SEXP Rf_ScalarLogical(int value) {
 
 SEXP Rf_allocVector3(SEXPTYPE t, R_xlen_t len, R_allocator_t* allocator) {
     if (allocator != NULL) {
-	unimplemented("RF_allocVector with custom allocator");
-	return NULL;
+  	    unimplemented("RF_allocVector with custom allocator");
+	    return NULL;
     }
-    TRACE(TARG2d, t, len);
+    TRACE(TARGpd, t, len);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_allocateVectorMethodID, t, len);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_allocArray(SEXPTYPE t, SEXP dims) {
-	TRACE(TARG2d, t, dims);
+	TRACE(TARGppd, t, dims);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_allocateArrayMethodID, t, dims);
 	return checkRef(thisenv, result);
@@ -268,7 +307,7 @@ SEXP Rf_alloc3DArray(SEXPTYPE t, int x, int y, int z) {
 }
 
 SEXP Rf_allocMatrix(SEXPTYPE mode, int nrow, int ncol) {
-	TRACE(TARG2d, mode, nrow, ncol);
+	TRACE(TARGppd, mode, nrow, ncol);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_allocateMatrixMethodID, mode, nrow, ncol);
 	return checkRef(thisenv, result);
@@ -284,12 +323,14 @@ SEXP Rf_allocSExp(SEXPTYPE t) {
 }
 
 SEXP Rf_cons(SEXP car, SEXP cdr) {
+	TRACE(TARGpp, car, cdr);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_consMethodID, car, cdr);
     return checkRef(thisenv, result);
 }
 
 void Rf_defineVar(SEXP symbol, SEXP value, SEXP rho) {
+	TRACE(TARGppp, symbol, value, rho);
 	JNIEnv *thisenv = getEnv();
 	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_defineVarMethodID, symbol, value, rho);
 }
@@ -307,48 +348,63 @@ SEXP Rf_dimnamesgets(SEXP x, SEXP y) {
 }
 
 SEXP Rf_eval(SEXP expr, SEXP env) {
+	TRACE(TARGpp, expr, env);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_evalMethodID, expr, env);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_findFun(SEXP symbol, SEXP rho) {
+	TRACE(TARGpp, symbol, rho);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findfunMethodID, symbol, rho);
 	return checkRef(thisenv, result);
 }
 
-SEXP Rf_findVar(SEXP symbol, SEXP rho) {
+SEXP Rf_findVar(SEXP sym, SEXP rho) {
+	TRACE(TARGpp, sym, rho);
+	JNIEnv *thisenv = getEnv();
+	SEXP result =(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarMethodID, sym, rho);
+    return checkRef(thisenv, result);
+}
+
+SEXP Rf_findVarInFrame(SEXP rho, SEXP sym) {
+	TRACE(TARGpp, rho, sym);
 	JNIEnv *thisenv = getEnv();
-	SEXP result =(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarMethodID, symbol, rho);
+	SEXP result =(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarInFrameMethodID, rho, sym);
     return checkRef(thisenv, result);
 }
 
-SEXP Rf_findVarInFrame(SEXP symbol, SEXP rho) {
+SEXP Rf_findVarInFrame3(SEXP rho, SEXP sym, Rboolean b) {
+	TRACE(TARGppd, rho, sym, b);
 	JNIEnv *thisenv = getEnv();
-	SEXP result =(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarInFrameMethodID, symbol, rho);
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarInFrame3MethodID, rho, sym, b);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_getAttrib(SEXP vec, SEXP name) {
+	TRACE(TARGpp, vec, name);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_getAttribMethodID, vec, name);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_setAttrib(SEXP vec, SEXP name, SEXP val) {
+	TRACE(TARGppp, vec,name, val);
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_setAttribMethodID, vec, name, val);
+	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, Rf_setAttribMethodID, vec, name, val);
 	return val;
 }
 
 SEXP Rf_duplicate(SEXP x) {
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_duplicateMethodID, x);
 	return checkRef(thisenv, result);
 }
 
 R_xlen_t Rf_any_duplicated(SEXP x, Rboolean from_last) {
+	TRACE(TARGpd, x, from_last);
     if (!isVector(x)) error(_("'duplicated' applies only to vectors"));
 	JNIEnv *thisenv = getEnv();
     return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_anyDuplicatedMethodID, x, from_last);
@@ -371,7 +427,12 @@ void Rf_copyVector(SEXP x, SEXP y) {
 	unimplemented("Rf_copyVector");
 }
 
+int Rf_countContexts(int x, int y) {
+	return (int) unimplemented("Rf_countContexts");
+}
+
 Rboolean Rf_inherits(SEXP x, const char * klass) {
+	TRACE(TARGps, x, klass);
     JNIEnv *thisenv = getEnv();
     jstring klazz = (*thisenv)->NewStringUTF(thisenv, klass);
     return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_inheritsMethodID, x, klazz);
@@ -411,6 +472,7 @@ void Rf_PrintValue(SEXP x) {
 }
 
 SEXP Rf_install(const char *name) {
+	TRACE(TARGs, name);
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, name);
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, createSymbolMethodID, string);
@@ -418,7 +480,7 @@ SEXP Rf_install(const char *name) {
 }
 
 SEXP Rf_installChar(SEXP charsxp) {
-	TRACE("%s(%p)\n", charsxp);
+	TRACE(TARGp, charsxp);
 	JNIEnv *thisenv = getEnv();
 	jstring string = stringFromCharSXP(thisenv, charsxp);
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, createSymbolMethodID, string);
@@ -459,6 +521,7 @@ SEXP Rf_mkCharLen(const char *x, int y) {
 }
 
 SEXP Rf_mkCharLenCE(const char *x, int len, cetype_t enc) {
+	TRACE(TARGsdd, x, len, enc);
 	JNIEnv *thisenv = getEnv();
 	jbyteArray bytes = (*thisenv)->NewByteArray(thisenv, len);
 	(*thisenv)->SetByteArrayRegion(thisenv, bytes, 0, len, x);
@@ -487,24 +550,25 @@ int Rf_nrows(SEXP x) {
 
 
 SEXP Rf_protect(SEXP x) {
+	TRACE(TARGp, x);
 	return x;
 }
 
 void Rf_unprotect(int x) {
-	// TODO perhaps we can use this
+	TRACE(TARGp, x);
 }
 
 void R_ProtectWithIndex(SEXP x, PROTECT_INDEX *y) {
-
+	TRACE(TARGpd, x,y);
 }
 
 void R_Reprotect(SEXP x, PROTECT_INDEX y) {
-
+	TRACE(TARGpd, x,y);
 }
 
 
 void Rf_unprotect_ptr(SEXP x) {
-	// TODO perhaps we can use this
+	TRACE(TARGp, x);
 }
 
 #define BUFSIZE 8192
@@ -625,31 +689,28 @@ SEXP Rf_classgets(SEXP x, SEXP y) {
 }
 
 const char *Rf_translateChar(SEXP x) {
-//	unimplemented("Rf_translateChar");
 	// TODO: proper implementation
+	TRACE(TARGp, x);
 	const char *result = CHAR(x);
-//	printf("translateChar: '%s'\n", result);
 	return result;
 }
 
 const char *Rf_translateChar0(SEXP x) {
-	unimplemented("Rf_translateChar0");
-	return NULL;
+	// TODO: proper implementation
+	TRACE(TARGp, x);
+	const char *result = CHAR(x);
+	return result;
 }
 
 const char *Rf_translateCharUTF8(SEXP x) {
-	unimplemented("Rf_translateCharUTF8");
-	return NULL;
-}
-
-SEXP R_FindNamespace(SEXP info) {
-	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_FindNamespaceMethodID, info);
-	return checkRef(thisenv, result);
+	// TODO: proper implementation
+	TRACE(TARGp, x);
+	const char *result = CHAR(x);
+	return result;
 }
 
 SEXP Rf_lengthgets(SEXP x, R_len_t y) {
-	TRACE("%s(%p)\n", x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	invalidateCopiedObject(thisenv, x);
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_lengthgetsMethodID, x, y);
@@ -661,6 +722,16 @@ SEXP Rf_xlengthgets(SEXP x, R_xlen_t y) {
 
 }
 
+SEXP R_lsInternal(SEXP env, Rboolean all) {
+	return R_lsInternal3(env, all, TRUE);
+}
+
+SEXP R_lsInternal3(SEXP env, Rboolean all, Rboolean sorted) {
+	JNIEnv *thisenv = getEnv();
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_lsInternal3MethodID, env, all, sorted);
+	return checkRef(thisenv, result);
+}
+
 SEXP Rf_namesgets(SEXP x, SEXP y) {
 	return unimplemented("Rf_namesgets");
 }
@@ -733,28 +804,28 @@ void Rf_gsetVar(SEXP symbol, SEXP value, SEXP rho)
 }
 
 SEXP TAG(SEXP e) {
-    TRACE(TARG1, e);
+    TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, TAG_MethodID, e);
     return checkRef(thisenv, result);
 }
 
 SEXP PRINTNAME(SEXP e) {
-    TRACE(TARG1, e);
+    TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, PRINTNAME_MethodID, e);
     return checkRef(thisenv, result);
 }
 
 SEXP CAR(SEXP e) {
-    TRACE(TARG1, e);
+    TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CAR_MethodID, e);
     return checkRef(thisenv, result);
 }
 
 SEXP CDR(SEXP e) {
-    TRACE(TARG1, e);
+    TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CDR_MethodID, e);
     return checkRef(thisenv, result);
@@ -771,7 +842,7 @@ SEXP CDAR(SEXP e) {
 }
 
 SEXP CADR(SEXP e) {
-    TRACE(TARG1, e);
+    TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CADR_MethodID, e);
     return checkRef(thisenv, result);
@@ -814,20 +885,20 @@ void SET_MISSING(SEXP x, int v) {
 }
 
 void SET_TAG(SEXP x, SEXP y) {
-    TRACE(TARG2, x, y);
+    TRACE(TARGpp, x, y);
     JNIEnv *thisenv = getEnv();
     (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SET_TAG_MethodID, x, y);
 }
 
 SEXP SETCAR(SEXP x, SEXP y) {
-    TRACE(TARG2, x, y);
+    TRACE(TARGpp, x, y);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SETCAR_MethodID, x, y);
     return checkRef(thisenv, result);
 }
 
 SEXP SETCDR(SEXP x, SEXP y) {
-    TRACE(TARG2, x, y);
+    TRACE(TARGpp, x, y);
     JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SETCDR_MethodID, x, y);
     return checkRef(thisenv, result);
@@ -866,13 +937,13 @@ SEXP CLOENV(SEXP x) {
 }
 
 int RDEBUG(SEXP x) {
-    unimplemented("RDEBUG");
-    return 0;
+    JNIEnv *thisenv = getEnv();
+    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, RDEBUGMethodID, x);
 }
 
 int RSTEP(SEXP x) {
-	unimplemented("RSTEP");
-    return 0;
+    JNIEnv *thisenv = getEnv();
+    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, RSTEPMethodID, x);
 }
 
 int RTRACE(SEXP x) {
@@ -881,11 +952,13 @@ int RTRACE(SEXP x) {
 }
 
 void SET_RDEBUG(SEXP x, int v) {
-    unimplemented("SET_RDEBUG");
+    JNIEnv *thisenv = getEnv();
+    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_RDEBUGMethodID, x, v);
 }
 
 void SET_RSTEP(SEXP x, int v) {
-    unimplemented("SET_RSTEP");
+    JNIEnv *thisenv = getEnv();
+    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_RSTEPMethodID, x, v);
 }
 
 void SET_RTRACE(SEXP x, int v) {
@@ -905,7 +978,9 @@ void SET_CLOENV(SEXP x, SEXP v) {
 }
 
 SEXP SYMVALUE(SEXP x) {
-	return unimplemented("SYMVALUE");
+    JNIEnv *thisenv = getEnv();
+    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SYMVALUE_MethodID, x);
+    return checkRef(thisenv, result);
 }
 
 SEXP INTERNAL(SEXP x) {
@@ -922,20 +997,22 @@ void SET_DDVAL(SEXP x, int v) {
 }
 
 void SET_SYMVALUE(SEXP x, SEXP v) {
-    unimplemented("SET_SYMVALUE");
+	JNIEnv *thisenv = getEnv();
+	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_SYMVALUE_MethodID, x, v);
 }
 
 void SET_INTERNAL(SEXP x, SEXP v) {
     unimplemented("SET_INTERNAL");
 }
 
-
 SEXP FRAME(SEXP x) {
 	return unimplemented("FRAME");
 }
 
 SEXP ENCLOS(SEXP x) {
-	return unimplemented("ENCLOS");
+	JNIEnv *thisenv = getEnv();
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, ENCLOSMethodID, x);
+    return checkRef(thisenv, result);
 }
 
 SEXP HASHTAB(SEXP x) {
@@ -974,7 +1051,9 @@ SEXP PRENV(SEXP x) {
 }
 
 SEXP PRVALUE(SEXP x) {
-	return unimplemented("PRVALUE");
+    JNIEnv *thisenv = getEnv();
+    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, PRVALUEMethodID, x);
+    return checkRef(thisenv, result);
 }
 
 int PRSEEN(SEXP x) {
@@ -998,7 +1077,7 @@ void SET_PRCODE(SEXP x, SEXP v) {
 }
 
 int LENGTH(SEXP x) {
-    TRACE(TARG1, x);
+    TRACE(TARGp, x);
     JNIEnv *thisenv = getEnv();
     return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, LENGTH_MethodID, x);
 }
@@ -1049,60 +1128,30 @@ int SETLEVELS(SEXP x, int v){
 }
 
 int *LOGICAL(SEXP x){
-	TRACE(TARG1, x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	jint *data = (jint *) findCopiedObject(thisenv, x);
-	if (data == NULL) {
-	    jbyteArray byteArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, LOGICAL_MethodID, x);
-	    int len = (*thisenv)->GetArrayLength(thisenv, byteArray);
-	    jbyte* internalData = (*thisenv)->GetByteArrayElements(thisenv, byteArray, NULL);
-	    data = malloc(len * sizeof(int));
-	    for (int i = 0; i < len; i++) {
-	    	char value = internalData[i];
-	    	data[i] = value == 0 ? FALSE : value == 1 ? TRUE : NA_INTEGER;
-	    }
-	    (*thisenv)->ReleaseByteArrayElements(thisenv, byteArray, internalData, JNI_ABORT);
-	    addCopiedObject(thisenv, x, LGLSXP, byteArray, data);
-	}
+	jint *data = (jint *) getNativeArray(thisenv, x, LGLSXP);
 	return data;
 }
 
 int *INTEGER(SEXP x){
-	TRACE(TARG1, x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	jint *data = (jint *) findCopiedObject(thisenv, x);
-	if (data == NULL) {
-	    jintArray intArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, INTEGER_MethodID, x);
-	    int len = (*thisenv)->GetArrayLength(thisenv, intArray);
-	    data = (*thisenv)->GetIntArrayElements(thisenv, intArray, NULL);
-	    addCopiedObject(thisenv, x, INTSXP, intArray, data);
-	}
+	jint *data = (jint *) getNativeArray(thisenv, x, INTSXP);
 	return data;
 }
 
 
 Rbyte *RAW(SEXP x){
 	JNIEnv *thisenv = getEnv();
-	jbyte *data = (jbyte *) findCopiedObject(thisenv, x);
-	if (data == NULL) {
-	    jbyteArray byteArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, RAW_MethodID, x);
-	    int len = (*thisenv)->GetArrayLength(thisenv, byteArray);
-	    data = (*thisenv)->GetByteArrayElements(thisenv, byteArray, NULL);
-        addCopiedObject(thisenv, x, RAWSXP, byteArray, data);
-    }
-	return (Rbyte*) data;
+	Rbyte *data = (Rbyte*) getNativeArray(thisenv, x, RAWSXP);
+	return data;
 }
 
 
 double *REAL(SEXP x){
     JNIEnv *thisenv = getEnv();
-    jdouble *data = (jdouble *) findCopiedObject(thisenv, x);
-    if (data == NULL) {
-	jdoubleArray doubleArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, REAL_MethodID, x);
-	int len = (*thisenv)->GetArrayLength(thisenv, doubleArray);
-	data = (*thisenv)->GetDoubleArrayElements(thisenv, doubleArray, NULL);
-	addCopiedObject(thisenv, x, REALSXP, doubleArray, data);
-    }
+    jdouble *data = (jdouble *) getNativeArray(thisenv, x, REALSXP);
     return data;
 }
 
@@ -1114,7 +1163,7 @@ Rcomplex *COMPLEX(SEXP x){
 
 
 SEXP STRING_ELT(SEXP x, R_xlen_t i){
-	TRACE(TARG2d, x, i);
+	TRACE(TARGpd, x, i);
 	JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, STRING_ELT_MethodID, x, i);
     return checkRef(thisenv, result);
@@ -1122,7 +1171,7 @@ SEXP STRING_ELT(SEXP x, R_xlen_t i){
 
 
 SEXP VECTOR_ELT(SEXP x, R_xlen_t i){
-	TRACE(TARG2d, x, i);
+	TRACE(TARGpd, x, i);
 	JNIEnv *thisenv = getEnv();
     SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, VECTOR_ELT_MethodID, x, i);
     return checkRef(thisenv, result);
@@ -1155,14 +1204,14 @@ SEXP *VECTOR_PTR(SEXP x){
 }
 
 SEXP Rf_asChar(SEXP x){
-	TRACE(TARG1, x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_asCharMethodID, x);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_PairToVectorList(SEXP x){
-	TRACE(TARG1, x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_PairToVectorListMethodID, x);
 	return checkRef(thisenv, result);
@@ -1179,19 +1228,19 @@ SEXP Rf_asCharacterFactor(SEXP x){
 }
 
 int Rf_asLogical(SEXP x){
-	TRACE(TARG1, x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_asLogicalMethodID, x);
 }
 
 int Rf_asInteger(SEXP x) {
-	TRACE(TARG1, x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_asIntegerMethodID, x);
 }
 
 //double Rf_asReal(SEXP x) {
-//	TRACE(TARG1, x);
+//	TRACE(TARGp, x);
 //	JNIEnv *thisenv = getEnv();
 //	return (*thisenv)->CallStaticDoubleMethod(thisenv, CallRFFIHelperClass, Rf_asRealMethodID, x);
 //}
@@ -1202,7 +1251,7 @@ Rcomplex Rf_asComplex(SEXP x){
 }
 
 int TYPEOF(SEXP x) {
-	TRACE(TARG1, x);
+	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, TYPEOF_MethodID, x);
 }
@@ -1272,15 +1321,8 @@ char *dngettext(const char *domainname, const char *msgid, const char * msgid_pl
 const char *R_CHAR(SEXP charsxp) {
 	TRACE("%s(%p)", charsxp);
 	JNIEnv *thisenv = getEnv();
-	// This is nasty:
-	// 1. the resulting character array has to be copied and zero-terminated.
-	// 2. It causes an (inevitable?) memory leak
 	jstring string = stringFromCharSXP(thisenv, charsxp);
-	jsize len = (*thisenv)->GetStringUTFLength(thisenv, string);
-	const char *stringChars = (*thisenv)->GetStringUTFChars(thisenv, string, NULL);
-	char *copyChars = malloc(len + 1);
-	memcpy(copyChars, stringChars, len);
-	copyChars[len] = 0;
+	char *copyChars = stringToChars(thisenv, string);
 	TRACE(" %s(%s)\n", copyChars);
 	return copyChars;
 }
@@ -1325,7 +1367,12 @@ void UNSET_S4_OBJECT(SEXP x) {
 }
 
 Rboolean R_ToplevelExec(void (*fun)(void *), void *data) {
-	return (Rboolean) unimplemented("R_ToplevelExec");
+	JNIEnv *env = getEnv();
+	jobject handlerStacks = (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, resetAndGetHandlerStacksMethodID);
+	fun(data);
+	(*env)->CallStaticVoidMethod(env, CallRFFIHelperClass, restoreHandlerStacksMethodID, handlerStacks);
+	// TODO how do we detect error
+	return TRUE;
 }
 
 SEXP R_ExecWithCleanup(SEXP (*fun)(void *), void *data,
@@ -1333,12 +1380,95 @@ SEXP R_ExecWithCleanup(SEXP (*fun)(void *), void *data,
 	return unimplemented("R_ExecWithCleanup");
 }
 
-SEXP R_tryEval(SEXP x, SEXP y, int *z) {
-	return unimplemented("R_tryEval");
+/* Environment and Binding Features */
+void R_RestoreHashCount(SEXP rho) {
+	unimplemented("R_RestoreHashCount");
 }
 
-SEXP R_tryEvalSilent(SEXP x, SEXP y, int *z) {
-	return unimplemented("R_tryEvalSilent");
+Rboolean R_IsPackageEnv(SEXP rho) {
+	unimplemented("R_IsPackageEnv");
+}
+
+SEXP R_PackageEnvName(SEXP rho) {
+	return unimplemented("R_PackageEnvName");
+}
+
+SEXP R_FindPackageEnv(SEXP info) {
+	return unimplemented("R_FindPackageEnv");
+}
+
+Rboolean R_IsNamespaceEnv(SEXP rho) {
+	return (Rboolean) unimplemented("R_IsNamespaceEnv");
+}
+
+SEXP R_NamespaceEnvSpec(SEXP rho) {
+	return unimplemented("R_NamespaceEnvSpec");
+}
+
+SEXP R_FindNamespace(SEXP info) {
+	JNIEnv *thisenv = getEnv();
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_FindNamespaceMethodID, info);
+	return checkRef(thisenv, result);
+}
+
+void R_LockEnvironment(SEXP env, Rboolean bindings) {
+	unimplemented("R_LockEnvironment");
+}
+
+Rboolean R_EnvironmentIsLocked(SEXP env) {
+	unimplemented("");
+}
+
+void R_LockBinding(SEXP sym, SEXP env) {
+	unimplemented("R_LockBinding");
+}
+
+void R_unLockBinding(SEXP sym, SEXP env) {
+	unimplemented("R_unLockBinding");
+}
+
+void R_MakeActiveBinding(SEXP sym, SEXP fun, SEXP env) {
+	unimplemented("R_MakeActiveBinding");
+}
+
+Rboolean R_BindingIsLocked(SEXP sym, SEXP env) {
+	JNIEnv *thisenv = getEnv();
+	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, R_BindingIsLockedID, sym, env);
+}
+
+Rboolean R_BindingIsActive(SEXP sym, SEXP env) {
+    // TODO: for now, I belive all bindings are false
+    return (Rboolean)0;
+}
+
+Rboolean R_HasFancyBindings(SEXP rho) {
+	return (Rboolean) unimplemented("R_HasFancyBindings");
+}
+
+Rboolean Rf_isS4(SEXP x) {
+    return IS_S4_OBJECT(x);
+}
+
+SEXP Rf_asS4(SEXP x, Rboolean b, int i) {
+	unimplemented("Rf_asS4");
+}
+
+static SEXP R_tryEvalInternal(SEXP x, SEXP y, int *ErrorOccurred, jboolean silent) {
+	JNIEnv *thisenv = getEnv();
+	jobject tryResult =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_tryEvalMethodID, x, y, silent);
+	// If tryResult is NULL, an error occurred
+	if (ErrorOccurred) {
+		*ErrorOccurred = tryResult == NULL;
+	}
+	return checkRef(thisenv, tryResult);
+}
+
+SEXP R_tryEval(SEXP x, SEXP y, int *ErrorOccurred) {
+	return R_tryEvalInternal(x, y, ErrorOccurred, JNI_FALSE);
+}
+
+SEXP R_tryEvalSilent(SEXP x, SEXP y, int *ErrorOccurred) {
+	return R_tryEvalInternal(x, y, ErrorOccurred, JNI_TRUE);
 }
 
 double R_atof(const char *str) {
@@ -1425,6 +1555,26 @@ void R_RunPendingFinalizers(void) {
 	// TODO implement, but not fail for now
 }
 
+SEXP R_MakeWeakRef(SEXP key, SEXP val, SEXP fin, Rboolean onexit) {
+	unimplemented("R_MakeWeakRef");
+}
+
+SEXP R_MakeWeakRefC(SEXP key, SEXP val, R_CFinalizer_t fin, Rboolean onexit) {
+	unimplemented("R_MakeWeakRefC");
+}
+
+SEXP R_WeakRefKey(SEXP w) {
+	unimplemented("R_WeakRefKey");
+}
+
+SEXP R_WeakRefValue(SEXP w) {
+	unimplemented("R_WeakRefValue");
+}
+
+void R_RunWeakRefFinalizer(SEXP w) {
+	// TODO implement, but not fail for now
+}
+
 SEXP R_do_slot(SEXP obj, SEXP name) {
 	return unimplemented("R_do_slot");
 }
@@ -1467,6 +1617,11 @@ void R_ReleaseObject(SEXP x) {
 	// Not applicable
 }
 
+void R_dot_Last(void) {
+	unimplemented("R_dot_Last");
+}
+
+
 Rboolean R_compute_identical(SEXP x, SEXP y, int flags) {
 	JNIEnv *thisenv = getEnv();
 	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, R_computeIdenticalMethodID, x, y, flags);
@@ -1474,10 +1629,10 @@ Rboolean R_compute_identical(SEXP x, SEXP y, int flags) {
 
 void Rf_copyListMatrix(SEXP s, SEXP t, Rboolean byrow) {
 	JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_copyListMatrixMethodID, s, t, byrow);  
+    (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_copyListMatrixMethodID, s, t, byrow);
 }
 
 void Rf_copyMatrix(SEXP s, SEXP t, Rboolean byrow) {
 	JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_copyMatrixMethodID, s, t, byrow);  
+    (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_copyMatrixMethodID, s, t, byrow);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c b/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c
index 58108f865ec3476fd78f1b4cfdf27db5d6788d6d..a8d153d4a0c39265d82c94e63c739c61e1c7a777 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c
@@ -34,6 +34,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_initialize(JNIEnv *env,
 	init_internals(env);
 	init_rmath(env);
 	init_random(env);
+	init_parse(env);
 }
 
 JNIEXPORT void JNICALL
@@ -1233,5 +1234,13 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_callVoid0(JNIEnv *env, j
 	callExit(env);
 }
 
+#include <Rinterface.h>
+
+JNIEXPORT void JNICALL
+Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_nativeSetInteractive(JNIEnv *env, jclass c, jboolean interactive) {
+	R_Interactive = interactive;
+}
+
+
 
 
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
index f009ca873b9f5227f8689deadb794c71fcaae750..43f13021a505226076c73c73e19162c98ce54186 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
@@ -23,14 +23,14 @@
 #include <rffiutils.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 /*
  * All calls pass through one of the call(N) methods in rfficall.c, which carry the JNIEnv value,
  * that needs to be saved for reuse in the many R functions such as Rf_allocVector.
  * Currently only single threaded access is permitted (via a semaphore in CallRFFIWithJNI)
  * so we are safe to use static variables. TODO Figure out where to store such state
- * (portably) for MT use. JNI provides no help. N.B. The MT restriction also precludes
- * recursive calls.
+ * (portably) for MT use. JNI provides no help.
  */
 jclass CallRFFIHelperClass;
 jclass RDataFactoryClass;
@@ -42,33 +42,70 @@ static jmethodID unimplementedMethodID;
 jmethodID createSymbolMethodID;
 static jmethodID validateMethodID;
 
-JNIEnv *curenv = NULL;
+static JNIEnv *curenv = NULL;
 jmp_buf *callErrorJmpBuf;
 
-#define DEBUG_CACHE 0
-#define TRACE_COPIES 0
-#define CACHED_GLOBALREFS_TABLE_SIZE 100
-static SEXP cachedGlobalRefs[CACHED_GLOBALREFS_TABLE_SIZE];
-static SEXP checkCachedGlobalRef(JNIEnv *env, SEXP obj);
+// default for trace output when enabled
+FILE *traceFile = NULL;
 
-typedef struct CopiedVectors_struct {
+static int alwaysUseGlobal = 0;
+#define CACHED_GLOBALREFS_INITIAL_SIZE 64
+static SEXP *cachedGlobalRefs;
+static int cachedGlobalRefsLength;
+
+// Data structure for managing the required copying of
+// Java arrays to return C arrays, e.g, int*.
+// N.B. There are actually two levels to this as FastR
+// wraps, e.g.,  int[] in an RIntVector.
+typedef struct nativeArrayTable_struct {
 	SEXPTYPE type;
-	SEXP obj;
-	void *jArray;
-	void *data;
-} CopiedVector;
+	SEXP obj;         // The jobject (SEXP) that data is derived from (e.g, RIntVector)
+	void *jArray;     // the jarray corresponding to obj
+	void *data;       // the (possibly) copied (or pinned) data from JNI GetXXXArrayElements
+} NativeArrayElem;
 
-#define COPIED_VECTORS_INITIAL_SIZE 100
+#define NATIVE_ARRAY_TABLE_INITIAL_SIZE 64
 // A table of vectors that have been accessed and whose contents, e.g. the actual data
 // as a primitive array have been copied and handed out to the native code.
-static CopiedVector *copiedVectors;
-// hwm of copiedVectors
-static int copiedVectorsIndex;
-static int copiedVectorsLength;
+static NativeArrayElem *nativeArrayTable;
+// hwm of nativeArrayTable
+static int nativeArrayTableHwm;
+static int nativeArrayTableLength;
+static void releaseNativeArray(JNIEnv *env, int index);
+
+static int isEmbedded = 0;
+void setEmbedded() {
+	isEmbedded = 1;
+}
 
+// native down call depth, indexes nativeArrayTableHwmStack
+int callDepth;
+
+#define NATIVE_ARRAY_TABLE_HWM_STACK_SIZE 16
+int nativeArrayTableHwmStack[NATIVE_ARRAY_TABLE_HWM_STACK_SIZE] ;
 
 void init_utils(JNIEnv *env) {
 	curenv = env;
+	if (TRACE_ENABLED && traceFile == NULL) {
+		if (!isEmbedded) {
+			traceFile = stdout;
+		} else {
+			jclass RFFIUtilsClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/RFFIUtils");
+			jclass FileDescriptorClass = checkFindClass(env, "java/io/FileDescriptor");
+			jmethodID getTraceFileDescriptorMethodID = checkGetMethodID(env, RFFIUtilsClass, "getTraceFileDescriptor", "()Ljava/io/FileDescriptor;", 1);
+			// ASSUMPTION: FileDescriptor has an "fd" field
+			jobject tfd = (*env)->CallStaticObjectMethod(env, RFFIUtilsClass, getTraceFileDescriptorMethodID);
+			jfieldID fdField = checkGetFieldID(env, FileDescriptorClass, "fd", "I", 0);
+			int fd = (*env)->GetIntField(env, tfd, fdField);
+		    traceFile = fdopen(fd, "w");
+		    if (traceFile == NULL) {
+				fprintf(stderr, "%s, %d", "failed to fdopen trace file on JNI side\n", errno);
+				exit(1);
+			}
+		    // no buffering
+		    setvbuf(traceFile, (char*) NULL, _IONBF, 0);
+		}
+	}
 	RDataFactoryClass = checkFindClass(env, "com/oracle/truffle/r/runtime/data/RDataFactory");
 	CallRFFIHelperClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper");
 	RRuntimeClass = checkFindClass(env, "com/oracle/truffle/r/runtime/RRuntime");
@@ -76,169 +113,257 @@ void init_utils(JNIEnv *env) {
 	unimplementedMethodID = checkGetMethodID(env, RInternalErrorClass, "unimplemented", "(Ljava/lang/String;)Ljava/lang/RuntimeException;", 1);
 	createSymbolMethodID = checkGetMethodID(env, RDataFactoryClass, "createSymbolInterned", "(Ljava/lang/String;)Lcom/oracle/truffle/r/runtime/data/RSymbol;", 1);
     validateMethodID = checkGetMethodID(env, CallRFFIHelperClass, "validate", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-    for (int i = 0; i < CACHED_GLOBALREFS_TABLE_SIZE; i++) {
-    	cachedGlobalRefs[i] = NULL;
-    }
-	copiedVectors = malloc(sizeof(CopiedVector) * COPIED_VECTORS_INITIAL_SIZE);
-	copiedVectorsLength = COPIED_VECTORS_INITIAL_SIZE;
-	copiedVectorsIndex = 0;
+    cachedGlobalRefs = calloc(CACHED_GLOBALREFS_INITIAL_SIZE, sizeof(SEXP));
+    cachedGlobalRefsLength = CACHED_GLOBALREFS_INITIAL_SIZE;
+	nativeArrayTable = calloc(NATIVE_ARRAY_TABLE_INITIAL_SIZE, sizeof(NativeArrayElem));
+	nativeArrayTableLength = NATIVE_ARRAY_TABLE_INITIAL_SIZE;
+	nativeArrayTableHwm = 0;
+}
+
+const char *stringToChars(JNIEnv *jniEnv, jstring string) {
+	// This is nasty:
+	// 1. the resulting character array has to be copied and zero-terminated.
+	// 2. It causes an (inevitable?) memory leak
+	jsize len = (*jniEnv)->GetStringUTFLength(jniEnv, string);
+	const char *stringChars = (*jniEnv)->GetStringUTFChars(jniEnv, string, NULL);
+	char *copyChars = malloc(len + 1);
+	memcpy(copyChars, stringChars, len);
+	copyChars[len] = 0;
+	return copyChars;
 }
 
 void callEnter(JNIEnv *env, jmp_buf *jmpbuf) {
 	setEnv(env);
 	callErrorJmpBuf = jmpbuf;
-//	printf("callEnter\n");
+	if (callDepth >= NATIVE_ARRAY_TABLE_HWM_STACK_SIZE) {
+		fatalError("call stack overflow\n");
+	}
+	nativeArrayTableHwmStack[callDepth] = nativeArrayTableHwm;
+	callDepth++;
 }
 
 jmp_buf *getErrorJmpBuf() {
 	return callErrorJmpBuf;
 }
 
-void releaseCopiedVector(JNIEnv *env, CopiedVector cv) {
-    if (cv.obj != NULL) {
-	switch (cv.type) {
-        case INTSXP: {
-	        jintArray intArray = (jintArray) cv.jArray;
-	        (*env)->ReleaseIntArrayElements(env, intArray, (jint *)cv.data, 0);
-	        break;
-        }
-
-        case LGLSXP: {
-        	// for LOGICAL, we need to convert back to 1-byte elements
-	        jintArray byteArray = (jbyteArray) cv.jArray;
-    	    int len = (*env)->GetArrayLength(env, byteArray);
-    	    jbyte* internalData = (*env)->GetByteArrayElements(env, byteArray, NULL);
-    	    int* data = (int*) cv.data;
-    	    for (int i = 0; i < len; i++) {
-    	    	internalData[i] = data[i] == NA_INTEGER ? 255 : (jbyte) data[i];
-    	    }
-    	    (*env)->ReleaseByteArrayElements(env, byteArray, internalData, 0);
-	        break;
-        }
-
-	    case REALSXP: {
-		    jdoubleArray doubleArray = (jdoubleArray) cv.jArray;
-		    (*env)->ReleaseDoubleArrayElements(env, doubleArray, (jdouble *)cv.data, 0);
-		    break;
-
-	    }
-
-	    case RAWSXP: {
-		    jbyteArray byteArray = (jbyteArray) cv.jArray;
-		    (*env)->ReleaseByteArrayElements(env, byteArray, (jbyte *)cv.data, 0);
-		    break;
-
-	    }
-	    default:
-		fatalError("copiedVector type");
-	}
-    }
-}
-
 void callExit(JNIEnv *env) {
-//	printf("callExit\n");
-	int i;
-	for (i = 0; i < copiedVectorsIndex; i++) {
-		releaseCopiedVector(env, copiedVectors[i]);
+	int oldHwm = nativeArrayTableHwmStack[callDepth - 1];
+	for (int i = oldHwm; i < nativeArrayTableHwm; i++) {
+		releaseNativeArray(env, i);
 	}
-	copiedVectorsIndex = 0;
+	nativeArrayTableHwm = oldHwm;
+	callDepth--;
 }
 
-void invalidateCopiedObject(JNIEnv *env, SEXP oldObj) {
+void invalidateNativeArray(JNIEnv *env, SEXP oldObj) {
 	int i;
-	for (i = 0; i < copiedVectorsIndex; i++) {
-		CopiedVector cv = copiedVectors[i];
+	for (i = 0; i < nativeArrayTableHwm; i++) {
+		NativeArrayElem cv = nativeArrayTable[i];
 		if ((*env)->IsSameObject(env, cv.obj, oldObj)) {
-#if TRACE_COPIES
-			printf("invalidateCopiedObject(%p): found\n", oldObj);
+#if TRACE_NATIVE_ARRAYS
+			fprintf(traceFile, "invalidateNativeArray(%p): found\n", oldObj);
 #endif
-			releaseCopiedVector(env, cv);
-			copiedVectors[i].obj = NULL;
+			releaseNativeArray(env, &cv);
+			nativeArrayTable[i].obj = NULL;
 		}
 	}
-#if TRACE_COPIES
-	printf("invalidateCopiedObject(%p): not found\n", oldObj);
+#if TRACE_NATIVE_ARRAYS
+	fprintf(traceFile, "invalidateNativeArray(%p): not found\n", oldObj);
 #endif
 }
 
-void *findCopiedObject(JNIEnv *env, SEXP x) {
+static void *findNativeArray(JNIEnv *env, SEXP x) {
 	int i;
-	for (i = 0; i < copiedVectorsIndex; i++) {
-		CopiedVector cv = copiedVectors[i];
-		if ((*env)->IsSameObject(env, cv.obj, x)) {
-			void *data = cv.data;
-#if TRACE_COPIES
-			printf("findCopiedObject(%p): found %p\n", x, data);
+	for (i = 0; i < nativeArrayTableHwm; i++) {
+		NativeArrayElem cv = nativeArrayTable[i];
+		if (cv.obj != NULL) {
+			if ((*env)->IsSameObject(env, cv.obj, x)) {
+				void *data = cv.data;
+#if TRACE_NATIVE_ARRAYS
+				fprintf(traceFile, "findNativeArray(%p): found %p\n", x, data);
 #endif
-			return data;
+				return data;
+			}
 		}
 	}
-#if TRACE_COPIES
-	printf("findCopiedObject(%p): not found\n", x);
+#if TRACE_NATIVE_ARRAYS
+	fprintf(traceFile, "findNativeArray(%p): not found\n", x);
 #endif
 	return NULL;
 }
 
-void addCopiedObject(JNIEnv *env, SEXP x, SEXPTYPE type, void *jArray, void *data) {
-#if TRACE_COPIES
-	printf("addCopiedObject(%p, %p)\n", x, data);
+static void addNativeArray(JNIEnv *env, SEXP x, SEXPTYPE type, void *jArray, void *data) {
+#if TRACE_NATIVE_ARRAYS
+	fprintf(traceFile, "addNativeArray(x=%p, t=%p, ix=%d)\n", x, data, nativeArrayTableHwm);
 #endif
-	if (copiedVectorsIndex >= copiedVectorsLength) {
-		int newLength = 2 * copiedVectorsLength;
-		CopiedVector *newCopiedVectors = malloc(sizeof(CopiedVector) * newLength);
-		if (newCopiedVectors == NULL) {
-			fatalError("malloc failure");
+	// check for overflow
+	if (nativeArrayTableHwm >= nativeArrayTableLength) {
+		int newLength = 2 * nativeArrayTableLength;
+		NativeArrayElem *newnativeArrayTable = calloc(newLength, sizeof(NativeArrayElem));
+		if (newnativeArrayTable == NULL) {
+			fatalError("FFI copied vectors table expansion failure");
 		}
-		memcpy(newCopiedVectors, copiedVectors, copiedVectorsLength * sizeof(CopiedVector));
-		free(copiedVectors);
-		copiedVectors = newCopiedVectors;
-		copiedVectorsLength = newLength;
+		memcpy(newnativeArrayTable, nativeArrayTable, nativeArrayTableLength * sizeof(NativeArrayElem));
+		free(nativeArrayTable);
+		nativeArrayTable = newnativeArrayTable;
+		nativeArrayTableLength = newLength;
 	}
-	copiedVectors[copiedVectorsIndex].obj = x;
-	copiedVectors[copiedVectorsIndex].data = data;
-	copiedVectors[copiedVectorsIndex].type = type;
-	copiedVectors[copiedVectorsIndex].jArray = jArray;
-	copiedVectorsIndex++;
-#if TRACE_COPIES
-	printf("copiedVectorsIndex: %d\n", copiedVectorsIndex);
-#endif
+	nativeArrayTable[nativeArrayTableHwm].obj = x;
+	nativeArrayTable[nativeArrayTableHwm].data = data;
+	nativeArrayTable[nativeArrayTableHwm].type = type;
+	nativeArrayTable[nativeArrayTableHwm].jArray = jArray;
+	nativeArrayTableHwm++;
 }
 
-SEXP checkRef(JNIEnv *env, SEXP obj) {
-	SEXP result = checkCachedGlobalRef(env, obj);
-	return result;
-}
+void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) {
+	void *data = findNativeArray(thisenv, x);
+	jboolean isCopy;
+	if (data == NULL) {
+		jarray jArray;
+		switch (type) {
+		case INTSXP: {
+			jintArray intArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, INTEGER_MethodID, x);
+			int len = (*thisenv)->GetArrayLength(thisenv, intArray);
+			data = (*thisenv)->GetIntArrayElements(thisenv, intArray, &isCopy);
+			jArray = intArray;
+			break;
+		}
+
+		case REALSXP: {
+			jdoubleArray doubleArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, REAL_MethodID, x);
+			int len = (*thisenv)->GetArrayLength(thisenv, doubleArray);
+			data = (*thisenv)->GetDoubleArrayElements(thisenv, doubleArray, &isCopy);
+			jArray = doubleArray;
+			break;
+		}
+
+		case RAWSXP: {
+		    jbyteArray byteArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, RAW_MethodID, x);
+		    int len = (*thisenv)->GetArrayLength(thisenv, byteArray);
+		    data = (*thisenv)->GetByteArrayElements(thisenv, byteArray, &isCopy);
+	        jArray = byteArray;
+	        break;
+		}
+
+		case LGLSXP: {
+			// Special treatment becuase R FFI wants int* and FastR represents using byte[]
+		    jbyteArray byteArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, LOGICAL_MethodID, x);
+		    int len = (*thisenv)->GetArrayLength(thisenv, byteArray);
+		    jbyte* internalData = (*thisenv)->GetByteArrayElements(thisenv, byteArray, &isCopy);
+		    int* idata = malloc(len * sizeof(int));
+		    for (int i = 0; i < len; i++) {
+		    	char value = internalData[i];
+		    	idata[i] = value == 0 ? FALSE : value == 1 ? TRUE : NA_INTEGER;
+		    }
+		    (*thisenv)->ReleaseByteArrayElements(thisenv, byteArray, internalData, JNI_ABORT);
+		    jArray = byteArray;
+		    data = idata;
+		    break;
+		}
 
-SEXP mkNamedGlobalRef(JNIEnv *env, int index, SEXP obj) {
-	SEXP result = (*env)->NewGlobalRef(env, obj);
-	if (cachedGlobalRefs[index] != NULL) {
-		fatalError("duplicate named global ref index\n");
+		default:
+			fatalError("getNativeArray: unexpected type");
+
+		}
+		addNativeArray(thisenv, x, type, jArray, data);
 	}
-	cachedGlobalRefs[index] = result;
-#if DEBUG_CACHE
-	printf("gref: %d=%p\n", index, result);
+	return data;
+}
+
+static void releaseNativeArray(JNIEnv *env, int i) {
+	NativeArrayElem cv = nativeArrayTable[i];
+#if TRACE_NATIVE_ARRAYS
+		fprintf(traceFile, "releaseNativeArray(x=%p, ix=%d)\n", cv.obj, i);
 #endif
-	return result;
+	if (cv.obj != NULL) {
+		switch (cv.type) {
+		case INTSXP: {
+			jintArray intArray = (jintArray) cv.jArray;
+			(*env)->ReleaseIntArrayElements(env, intArray, (jint *)cv.data, 0);
+			break;
+		}
+
+		case LGLSXP: {
+			// for LOGICAL, we need to convert back to 1-byte elements
+			jintArray byteArray = (jbyteArray) cv.jArray;
+			int len = (*env)->GetArrayLength(env, byteArray);
+			jbyte* internalData = (*env)->GetByteArrayElements(env, byteArray, NULL);
+			int* data = (int*) cv.data;
+			for (int i = 0; i < len; i++) {
+				internalData[i] = data[i] == NA_INTEGER ? 255 : (jbyte) data[i];
+			}
+			(*env)->ReleaseByteArrayElements(env, byteArray, internalData, 0);
+			free(data); // was malloc'ed in addNativeArray
+			break;
+		}
+
+		case REALSXP: {
+			jdoubleArray doubleArray = (jdoubleArray) cv.jArray;
+			(*env)->ReleaseDoubleArrayElements(env, doubleArray, (jdouble *)cv.data, 0);
+			break;
+
+		}
+
+		case RAWSXP: {
+			jbyteArray byteArray = (jbyteArray) cv.jArray;
+			(*env)->ReleaseByteArrayElements(env, byteArray, (jbyte *)cv.data, 0);
+			break;
+
+		}
+		default:
+			fatalError("releaseNativeArray type");
+		}
+		// free up the slot
+		cv.obj = NULL;
+	}
 }
 
-static SEXP checkCachedGlobalRef(JNIEnv *env, SEXP obj) {
-    for (int i = 0; i < CACHED_GLOBALREFS_TABLE_SIZE; i++) {
-    	SEXP ref = cachedGlobalRefs[i];
-    	if (ref == NULL) {
-    		break;
-    	}
-    	if ((*env)->IsSameObject(env, ref, obj)) {
-#if DEBUG_CACHE
-    		printf("gref: cache hit: %d\n", i);
+static SEXP checkCachedGlobalRef(JNIEnv *env, SEXP obj, int useGlobal) {
+	int i;
+	for (i = 0; i < cachedGlobalRefsLength; i++) {
+		SEXP ref = cachedGlobalRefs[i];
+		if (ref == NULL) {
+			break;
+		}
+		if ((*env)->IsSameObject(env, ref, obj)) {
+#if TRACE_REF_CACHE
+			fprintf(traceFile, "gref: cache hit: %d\n", i);
 #endif
-    		return ref;
-    	}
-    }
-#if USE_GLOBAL
-    SEXP result = (*env)->NewGlobalRef(env, obj);
-#else
-    SEXP result = obj;
+			return ref;
+		}
+	}
+	SEXP result;
+	if (useGlobal) {
+		if (i >= cachedGlobalRefsLength) {
+			int newLength = cachedGlobalRefsLength * 2;
+#if TRACE_REF_CACHE
+			fprintf(traceFile, "gref: extending table to %d\n", newLength);
 #endif
+			SEXP newCachedGlobalRefs = calloc(newLength, sizeof(SEXP));
+			if (newCachedGlobalRefs == NULL) {
+				fatalError("FFI global refs table expansion failure");
+			}
+			memcpy(newCachedGlobalRefs, cachedGlobalRefs, cachedGlobalRefsLength * sizeof(SEXP));
+			free(cachedGlobalRefs);
+			cachedGlobalRefs = newCachedGlobalRefs;
+			cachedGlobalRefsLength = newLength;
+		}
+		result = (*env)->NewGlobalRef(env, obj);
+		cachedGlobalRefs[i] = result;
+	} else {
+		result = obj;
+	}
+	return result;
+}
+
+SEXP checkRef(JNIEnv *env, SEXP obj) {
+	SEXP result = checkCachedGlobalRef(env, obj, alwaysUseGlobal);
+	TRACE(TARGp, result);
+	return result;
+}
+
+SEXP mkNamedGlobalRef(JNIEnv *env, SEXP obj) {
+	SEXP result = checkCachedGlobalRef(env, obj, 1);
 	return result;
 }
 
@@ -256,7 +381,7 @@ void validate(SEXP x) {
 }
 
 JNIEnv *getEnv() {
-//	printf("getEnv()=%p\n", curenv);
+//	fprintf(traceFile, "getEnv()=%p\n", curenv);
 	return curenv;
 }
 
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
index 24e89fee06e97133581fbffc8068055002666ba6..62da16cdcf08af4579691d82e5b5d7b427c627f7 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
@@ -48,8 +48,8 @@ void fatalError(char *msg);
 void validate(SEXP x);
 // checks x against the list of canonical (named) refs, returning the canonical version if a match
 SEXP checkRef(JNIEnv *env, SEXP x);
-// creates a JNI global ref from x for slot index of the named refs table
-SEXP mkNamedGlobalRef(JNIEnv *env, int index, SEXP x);
+// creates a canonical (named) JNI global ref from x
+SEXP mkNamedGlobalRef(JNIEnv *env, SEXP x);
 // validate a JNI reference
 void validateRef(JNIEnv *env, SEXP x, const char *msg);
 
@@ -62,11 +62,12 @@ void allocExit();
 
 jmp_buf *getErrorJmpBuf();
 
-// find an object for which we have cached the internal rep
-void *findCopiedObject(JNIEnv *env, SEXP x);
-// add a new object to the internal rep cache
-void addCopiedObject(JNIEnv *env, SEXP x, SEXPTYPE type, void *jArray, void *data);
-void invalidateCopiedObject(JNIEnv *env, SEXP oldObj);
+// Given the x denotes an R vector type, return a pointer to
+// the data as a C array
+void *getNativeArray(JNIEnv *env, SEXP x, SEXPTYPE type);
+// Rare case where an operation changes the internal
+// data and thus the old C array should be invalidated
+void invalidateNativeArray(JNIEnv *env, SEXP oldObj);
 
 void init_rmath(JNIEnv *env);
 void init_variables(JNIEnv *env, jobjectArray initialValues);
@@ -74,25 +75,48 @@ void init_dynload(JNIEnv *env);
 void init_internals(JNIEnv *env);
 void init_random(JNIEnv *env);
 void init_utils(JNIEnv *env);
+void init_parse(JNIEnv *env);
+
+void setEmbedded(void);
 
 void setTempDir(JNIEnv *, jstring tempDir);
 
 extern jclass RDataFactoryClass;
 extern jclass CallRFFIHelperClass;
 extern jclass RRuntimeClass;
-
-#define TRACE_UPCALLS 0
-
-#define TARG1 "%s(%p)\n"
-#define TARG2 "%s(%p, %p)\n"
-#define TARG2d "%s(%p, %d)\n"
+extern FILE *traceFile;
+
+// tracing/debugging support, set to 1 and recompile to enable
+#define TRACE_UPCALLS 0    // trace upcalls
+#define TRACE_REF_CACHE 0  // trace JNI reference cache
+#define TRACE_NATIVE_ARRAYS 0     // trace generation of internal arrays
+#define TRACE_ENABLED TRACE_UPCALLS || TRACE_REF_CACHE || TRACE_NATIVE_ARRAYS
+
+#define TARGp "%s(%p)\n"
+#define TARGpp "%s(%p, %p)\n"
+#define TARGppp "%s(%p, %p, %p)\n"
+#define TARGpd "%s(%p, %d)\n"
+#define TARGppd "%s(%p, %p, %d)\n"
+#define TARGs "%s(\"%s\")\n"
+#define TARGps "%s(%p, \"%s\")\n"
+#define TARGsdd "%s(\"%s\", %d, %d)\n"
 
 #if TRACE_UPCALLS
-#define TRACE(format, ...) printf(format, __FUNCTION__, __VA_ARGS__)
+#define TRACE(format, ...) fprintf(traceFile, format, __FUNCTION__, __VA_ARGS__)
 #else
 #define TRACE(format, ...)
 #endif
 
 #define _(Source) (Source)
 
+// convert a string into a char*
+const char *stringToChars(JNIEnv *jniEnv, jstring string);
+
+extern jmethodID INTEGER_MethodID;
+extern jmethodID LOGICAL_MethodID;
+extern jmethodID REAL_MethodID;
+extern jmethodID RAW_MethodID;
+
+extern int callDepth;
+
 #endif /* RFFIUTILS_H */
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/variables.c b/com.oracle.truffle.r.native/fficall/src/jni/variables.c
index d9c9497e38856a211840eb2d325389e871e17eef..328b067bd7ec76b0c201480912bc57097a77b9ae 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/variables.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/variables.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -27,7 +27,7 @@
 
 #include <string.h>
 #include <jni.h>
-#include <Rinternals.h>
+#include <Rinterface.h>
 #include <rffiutils.h>
 #include <variable_defs.h>
 
@@ -36,6 +36,7 @@ jmethodID getBaseEnvMethodID;
 jmethodID getBaseNamespaceMethodID;
 jmethodID getNamespaceRegistryMethodID;
 jmethodID isInteractiveMethodID;
+jmethodID getGlobalContextMethodID;
 
 // R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
 SEXP FASTR_GlobalEnv() {
@@ -58,12 +59,11 @@ SEXP FASTR_NamespaceRegistry() {
 	return (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getNamespaceRegistryMethodID);
 }
 
-Rboolean FASTR_IsInteractive() {
+CTXT FASTR_GlobalContext() {
 	JNIEnv *env = getEnv();
-	return (*env)->CallStaticIntMethod(env, CallRFFIHelperClass, isInteractiveMethodID);
+	return (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getGlobalContextMethodID);
 }
 
-
 void init_variables(JNIEnv *env, jobjectArray initialValues) {
 	// initialValues is an array of enums
 	jclass enumClass = (*env)->GetObjectClass(env, (*env)->GetObjectArrayElement(env, initialValues, 0));
@@ -81,10 +81,10 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) {
 	getBaseNamespaceMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getBaseNamespace", "()Ljava/lang/Object;", 1);
 	getNamespaceRegistryMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getNamespaceRegistry", "()Ljava/lang/Object;", 1);
 	isInteractiveMethodID = checkGetMethodID(env, CallRFFIHelperClass, "isInteractive", "()I", 1);
+	getGlobalContextMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getGlobalContext", "()Ljava/lang/Object;", 1);
 
 	int length = (*env)->GetArrayLength(env, initialValues);
 	int index;
-	int globalRefIndex = 0;
 	for (index = 0; index < length; index++) {
 		jobject variable = (*env)->GetObjectArrayElement(env, initialValues, index);
 		jstring nameString = (*env)->CallObjectMethod(env, variable, nameMethodID);
@@ -104,7 +104,7 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) {
 			} else if (strcmp(nameChars, "R_NaInt") == 0) {
 				R_NaInt = (*env)->CallIntMethod(env, value, intValueMethodID);
 			} else {
-				SEXP ref = mkNamedGlobalRef(env, globalRefIndex++, value);
+				SEXP ref = mkNamedGlobalRef(env, value);
 				if (strcmp(nameChars, "R_EmptyEnv") == 0) {
 					R_EmptyEnv = ref;
 				} else if (strcmp(nameChars, "R_NilValue") == 0) {
diff --git a/com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h b/com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h
index 7222c83482ecd0f9ce31908fe06119bca56a0a9c..9ab6cb36a2dd04d30fd90242b6955138ab369ccf 100644
--- a/com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h
+++ b/com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h
@@ -77,12 +77,14 @@ double R_NaReal;	/* NA_REAL: IEEE */
 int R_NaInt;	/* NA_INTEGER:= INT_MIN currently */
 
 // from Defn.h
-const char* R_Home;
+char* R_Home;
 const char* R_TempDir;
 
+// Set by a down call based on the setting in the initial context
+Rboolean R_Interactive;
+
 // various ignored flags and variables:
 Rboolean R_Visible;
-Rboolean R_Interactive;
 Rboolean R_interrupts_suspended;
 int R_interrupts_pending;
 Rboolean mbcslocale;
diff --git a/com.oracle.truffle.r.native/include/Makefile b/com.oracle.truffle.r.native/include/Makefile
index c65a01a741bce6b34c291cac88df46055d982a0a..5acbc6b49dc1a05ce37c7e19b4b2206bfe0803dd 100644
--- a/com.oracle.truffle.r.native/include/Makefile
+++ b/com.oracle.truffle.r.native/include/Makefile
@@ -44,12 +44,13 @@ R_HEADERS_TO_LINK := $(filter-out $(notdir $(R_HEADERS_LOCAL)),$(R_HEADERS_FILEN
 
 all: linked
 
-linked: ed_Rinternals ed_Rinterface ed_GraphicsEngine
+linked: ed_Rinternals ed_Rinterface_gcntx ed_Rinterface_interactive ed_GraphicsEngine
 	mkdir -p R_ext
 	$(foreach file,$(R_HEADERS_TO_LINK),ln -sf $(GNUR_HOME)/include/$(file) $(file);)
 	ln -sf src/libintl.h
 	ed $(GNUR_HOME)/include/Rinternals.h < ed_Rinternals
-	ed $(GNUR_HOME)/include/Rinterface.h < ed_Rinterface
+	ed $(GNUR_HOME)/include/Rinterface.h < ed_Rinterface_gcntx
+#	ed $(GNUR_HOME)/include/Rinterface.h < ed_Rinterface_interactive
 	ed $(GNUR_HOME)/include/R_ext/GraphicsEngine.h < ed_GraphicsEngine
 	$(foreach file,$(R_EXT_HEADERS_TO_LINK),ln -sf $(GNUR_HOME)/include/R_ext/$(file) R_ext/$(file);)
 #	cp $(R_EXT_HEADERS_LOCAL) R_ext
diff --git a/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx b/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx
new file mode 100644
index 0000000000000000000000000000000000000000..f9cf0613c24ce9f66f6d1c864deb23a289a24224
--- /dev/null
+++ b/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx
@@ -0,0 +1,21 @@
+/R_GlobalContext/
+i
+#ifdef FASTR
+typedef void *CTXT;
+typedef void *SEXP;
+extern CTXT FASTR_GlobalContext();
+#define R_GlobalContext FASTR_GlobalContext()
+extern CTXT R_getGlobalFunctionContext();
+extern CTXT R_getParentFunctionContext(CTXT);
+extern SEXP R_getContextEnv(CTXT);
+extern SEXP R_getContextFun(CTXT);
+extern SEXP R_getContextCall(CTXT);
+extern SEXP R_getContextSrcRef(CTXT);
+extern int R_insideBrowser();
+#else
+.
++1
+a
+#endif
+.
+w Rinterface.h
diff --git a/com.oracle.truffle.r.native/include/ed_Rinterface b/com.oracle.truffle.r.native/include/ed_Rinterface_interactive
similarity index 100%
rename from com.oracle.truffle.r.native/include/ed_Rinterface
rename to com.oracle.truffle.r.native/include/ed_Rinterface_interactive
diff --git a/com.oracle.truffle.r.native/run/Makefile b/com.oracle.truffle.r.native/run/Makefile
index 491f44da1a5fe2654e5dafa3956fc038dc8acc06..b445653a8b170c4f793c62fc5d44ed3e4ffc2d89 100644
--- a/com.oracle.truffle.r.native/run/Makefile
+++ b/com.oracle.truffle.r.native/run/Makefile
@@ -27,7 +27,7 @@
 # but in FastR it is just a slight variant of "R". However, we cannot put
 # a FastR-specific Rscript in "exec" because the install_packages code
 # treats everything in there except "R" as a sub-architecture, so we put in
-# execRscript.
+# execRextras.
 #
 # The R script defines the R_HOME environment variable from R_HOME_DIR
 # which is set in the script during the GnuR build. This has to be changed.
@@ -38,6 +38,7 @@
 .PHONY: bindir all rcmd
 
 FASTR_BIN_DIR := $(FASTR_R_HOME)/bin
+FASTR_DOC_DIR := $(FASTR_R_HOME)/doc
 FASTR_ETC_DIR := $(FASTR_R_HOME)/etc
 FASTR_SHARE_DIR := $(FASTR_R_HOME)/share
 FASTR_INCLUDE_DIR := $(FASTR_R_HOME)/include
@@ -45,6 +46,8 @@ FASTR_INCLUDE_DIR := $(FASTR_R_HOME)/include
 R_SCRIPT := $(addprefix $(GNUR_HOME)/bin/,R)
 SUPPORT_SCRIPTS := $(addprefix $(GNUR_HOME)/bin/,BATCH COMPILE INSTALL SHLIB Rcmd config javareconf)
 
+DOC_FILES := $(wildcard $(GNUR_HOME)/doc/*)
+
 # Not all of these work unchanged
 ETC_FILES := $(addprefix $(GNUR_HOME)/etc/,javaconf ldpaths Renviron repositories)
 
@@ -54,18 +57,20 @@ all: rundirs rcmds includedir
 
 rundirs:
 	mkdir -p $(FASTR_BIN_DIR)
+	mkdir -p $(FASTR_DOC_DIR)
 	mkdir -p $(FASTR_BIN_DIR)/exec
-	mkdir -p $(FASTR_BIN_DIR)/execRscript
+	mkdir -p $(FASTR_BIN_DIR)/execRextras
 	mkdir -p $(FASTR_ETC_DIR)
 	mkdir -p $(FASTR_SHARE_DIR)
 	
 rcmds: $(FASTR_BIN_DIR)/R
 
-$(FASTR_BIN_DIR)/R: Makefile R.sh Rscript.sh Rscript_exec.sh
+$(FASTR_BIN_DIR)/R: Makefile R.sh Rscript.sh Rscript_exec.sh Rclasspath.sh
 	cp R.sh $(FASTR_BIN_DIR)/exec/R
-	cp Rscript_exec.sh $(FASTR_BIN_DIR)/execRscript/Rscript
+	cp Rscript_exec.sh $(FASTR_BIN_DIR)/execRextras/Rscript
 	cp Rscript.sh $(FASTR_BIN_DIR)/Rscript
-	chmod +x $(FASTR_BIN_DIR)/exec/R $(FASTR_BIN_DIR)/execRscript/Rscript $(FASTR_BIN_DIR)/Rscript
+	cp Rclasspath.sh $(FASTR_BIN_DIR)/execRextras/Rclasspath
+	chmod +x $(FASTR_BIN_DIR)/exec/R $(FASTR_BIN_DIR)/execRextras/Rscript $(FASTR_BIN_DIR)/Rscript $(FASTR_BIN_DIR)/execRextras/Rclasspath
 	cp $(SUPPORT_SCRIPTS) $(FASTR_BIN_DIR)
 	sed -e 's!^\(R_HOME_DIR=\)\(.*\)!\1"$(FASTR_R_HOME)"!' < $(R_SCRIPT) > $(FASTR_BIN_DIR)/R
 	chmod +x $(FASTR_BIN_DIR)/R 
@@ -80,6 +85,8 @@ $(FASTR_BIN_DIR)/R: Makefile R.sh Rscript.sh Rscript_exec.sh
 	ed Makeconf.etc < edMakeconf.etc
 	cp Makeconf.etc $(FASTR_ETC_DIR)/Makeconf
 	cp -r $(SHARE_FILES) $(FASTR_SHARE_DIR)
+	# TODO may need filtering
+	cp -r $(DOC_FILES) $(FASTR_DOC_DIR)
 	# overrides
 	cp examples-header.R examples-footer.R $(FASTR_SHARE_DIR)/R
 
diff --git a/com.oracle.truffle.r.native/run/Rclasspath.sh b/com.oracle.truffle.r.native/run/Rclasspath.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1c01496f42293d7b4186d99f79098d840c69ff16
--- /dev/null
+++ b/com.oracle.truffle.r.native/run/Rclasspath.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# Copyright (c) 2016, 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
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# Retrieve JVM classpath (r-cp) using the mx tool (development)
+#
+
+#echo args="$@"
+#printenv | fgrep R_
+
+source="${BASH_SOURCE[0]}"
+while [ -h "$source" ] ; do source="$(readlink "$source")"; done
+PRIMARY_PATH="$( cd -P "$( dirname "$source" )" && pwd )"/../..
+
+which mx >/dev/null 2>&1
+whichrc=$?
+if [ $whichrc == 1 ] ; then
+    if [ -z "$MX_HOME" ] ; then
+	    echo "Error: mx cannot be found: add to PATH or set MX_HOME"
+	    exit 1
+    else
+	    mx=$MX_HOME/mx
+    fi
+else
+    mx=`which mx`
+fi
+
+exec $mx --primary-suite-path $PRIMARY_PATH $MX_R_GLOBAL_ARGS r-cp $MX_R_CMD_ARGS "$@"
diff --git a/com.oracle.truffle.r.native/run/Rscript.sh b/com.oracle.truffle.r.native/run/Rscript.sh
index 8098306855128274371cfda7c173533ad111a6e1..863b98abf20ca80373e3c3526df94c508ce74a34 100755
--- a/com.oracle.truffle.r.native/run/Rscript.sh
+++ b/com.oracle.truffle.r.native/run/Rscript.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2016, 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
@@ -24,10 +24,11 @@
 
 # In GnuR Rscript is an executable in the bin directory.
 # In FastR Rscript and R are combined in the same image. For consistency
-# Rscript is a script in the bin directory that simply invokes bin/exec/Rscript
+# Rscript is a script in the bin directory that simply invokes bin/execRextras/Rscript
+# N.B. This can't be in bin/exec as then it is treated as a sub0architecture
 
 source="${BASH_SOURCE[0]}"
 while [ -h "$source" ] ; do source="$(readlink "$source")"; done
 here="$( cd -P "$( dirname "$source" )" && pwd )"
 
-exec $here/execRscript/Rscript "$@"
+exec $here/execRextras/Rscript "$@"
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index 407c046347ac9264859cef58520cb7afb5f8ffc9..baa600759e5a7f148c1d9195bdd6bad536a4f611 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -136,6 +136,7 @@ public class BasePackage extends RBuiltinPackage {
         add(AsInteger.class, AsIntegerNodeGen::create);
         add(AsLogical.class, AsLogicalNodeGen::create);
         add(SetS4Object.class, SetS4ObjectNodeGen::create);
+        add(SetTimeLimit.class, SetTimeLimitNodeGen::create);
         add(AsRaw.class, AsRawNodeGen::create);
         add(AsVector.class, AsVectorNodeGen::create);
         add(Assign.class, AssignNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CapabilitiesFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CapabilitiesFunctions.java
index 9d9cf7ea93c4cb2e9abf7b9237251b77b1816814..9747ccc12e44080a9ec23d3b90fb4b82eeea13ce 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CapabilitiesFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CapabilitiesFunctions.java
@@ -26,7 +26,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RBuiltin;
 import com.oracle.truffle.r.runtime.RBuiltinKind;
-import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -82,7 +81,7 @@ public class CapabilitiesFunctions {
                 boolean value = c.defValue;
                 switch (c) {
                     case cledit:
-                        value = RContext.getInstance().isInteractive() && !RContext.getInstance().getOptions().getBoolean(RCmdOptions.RCmdOption.NO_READLINE);
+                        value = RContext.getInstance().isInteractive() && !RContext.getInstance().getStartParams().getNoReadline();
                         break;
                 }
                 data[c.ordinal()] = RRuntime.asLogical(value);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
index 3e8d4648468e8492c70ffb393d0aaf452f5fd0b8..afd74a557766e6a17bee79c8c0abaa18fa33ac88 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
@@ -178,6 +178,7 @@ public abstract class Combine extends RBuiltinNode {
     @ExplodeLoop
     private RStringVector foldNames(BranchProfile naNameBranch, NACheck naNameCheck, Object[] elements, int size) {
         RStringVector result = RDataFactory.createStringVector(new String[size], true);
+        result.incRefCount();
         int pos = 0;
         for (Object element : elements) {
             pos += processNamesElement(naNameBranch, naNameCheck, result, pos, element);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.java
index 9e784aad764cfe8bf3cc0ff1dac668a767e672af..c491925fb9f6dd92424951659659d279745f9400 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.java
@@ -38,7 +38,7 @@ public abstract class CommandArgs extends RBuiltinNode {
     @Specialization
     @TruffleBoundary
     protected RStringVector commandArgs() {
-        String[] s = RContext.getInstance().getOptions().getArguments();
+        String[] s = RContext.getInstance().getStartParams().getArguments();
         return RDataFactory.createStringVector(s, RDataFactory.COMPLETE_VECTOR);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
index ea11fe6090409d0ac2e7c776f8660900d6d43fc4..bc5e926c65cdcc4c46866e0449a6ebadceb97c6d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
@@ -67,6 +67,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
@@ -355,9 +356,7 @@ public class EnvFunctions {
             throw RError.error(this, RError.Message.USE_NULL_ENV_DEFUNCT);
         }
 
-        @Fallback
-        @TruffleBoundary
-        protected Object updateEnvironment(Object obj, Object env) {
+        protected Object updateEnvironmentNonFunction(Object obj, Object env) {
             if (env == RNull.instance || env instanceof REnvironment) {
                 if (obj instanceof RAttributable) {
                     RAttributable attributable = (RAttributable) obj;
@@ -374,6 +373,19 @@ public class EnvFunctions {
                 throw RError.error(this, RError.Message.REPLACEMENT_NOT_ENVIRONMENT);
             }
         }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object updateEnvironment(RAbstractContainer obj, Object env) {
+            return updateEnvironmentNonFunction(obj, env);
+        }
+
+        @Fallback
+        @TruffleBoundary
+        protected Object updateEnvironment(Object obj, Object env) {
+            return updateEnvironmentNonFunction(obj, env);
+        }
+
     }
 
     @RBuiltin(name = "environmentName", kind = INTERNAL, parameterNames = {"fun"})
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
index e4f7d1adfc512e70c91ff108ed198c78ba5411e1..086d37787874dca938a0708edace87eccf94702a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
@@ -57,7 +57,7 @@ public abstract class Format extends RBuiltinNode {
         if (printConfig == null) {
             printConfig = new Config();
         }
-        printConfig.width = RContext.getInstance().getConsoleHandler().getWidth();
+        printConfig.width = (int) RContext.getInstance().stateROptions.getValue("width");
         printConfig.naWidth = RRuntime.STRING_NA.length();
         printConfig.naWidthNoQuote = RRuntime.NA_HEADER.length();
         printConfig.digits = 7 /* default */;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
index 6de029a68e68a984b81fcd88e9c16c1421cbc9a7..c2f7807c20c3beed3310ea433b4780382dab178e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
@@ -40,9 +40,7 @@ public abstract class Gc extends RBuiltinNode {
     @SuppressWarnings("unused")
     @Specialization
     protected RDoubleVector gc(RAbstractLogicalVector verbose, RAbstractLogicalVector reset) {
-        // manually triggering gc in Java is typically not a terribly good idea so we don't do it
-        // here at all
-
+        System.gc();
         // TODO: somehow produce the (semi?) correct values
         double[] data = new double[14];
         Arrays.fill(data, RRuntime.DOUBLE_NA);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
index 8c7b35626d0a55c423737f508686f5f2abe4f34c..80f8c14c4dce9dea033f22e7a5a348821fbb437d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
@@ -809,6 +809,13 @@ public class GrepFunctions {
                         } else {
                             resultItem = splitIntl(data, currentSplit);
                         }
+                        if (resultItem.getLength() == 0) {
+                            if (fixed) {
+                                resultItem = RDataFactory.createStringVector(data);
+                            } else {
+                                resultItem = RDataFactory.createStringVector(data.length());
+                            }
+                        }
                     }
                     result[i] = resultItem;
                 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
index 3e8e95790e874c126b4481a9ebf75de9f6831aab..fd9176181cbeff8b626880e1ab6c876a2b9c62ca 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java
@@ -507,7 +507,7 @@ public abstract class PrettyPrinterNode extends RNode {
                 maxPositionLength = intString(vector.getLength()).length();
                 leftWidth = maxPositionLength + 2; // There is [] around the number.
             }
-            int forColumns = RContext.getInstance().getConsoleHandler().getWidth() - leftWidth;
+            int forColumns = (int) RContext.getInstance().stateROptions.getValue("width") - leftWidth;
             int numberOfColumns = Math.max(1, forColumns / columnWidth);
 
             int index = 0;
@@ -1723,7 +1723,7 @@ public abstract class PrettyPrinterNode extends RNode {
                 for (; colInd < dataColWidths.length; colInd++) {
                     boolean hasNegative = dataColWidths[colInd] < 0;
                     totalWidth += Math.abs(dataColWidths[colInd]) + ((isDoubleVector || isComplexVector) && hasNegative ? 2 : 1);
-                    if (totalWidth > RContext.getInstance().getConsoleHandler().getWidth()) {
+                    if (totalWidth > (int) RContext.getInstance().stateROptions.getValue("name")) {
                         if (colInd == startColInd) {
                             // the first column is already too wide but needs to be printed
                             // nevertheless
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
index b6f1ef4b27059cb5ca0df35a5e6a647a0035ba45..d8981ee372263777514a391e9597abcf9e7c23cc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
@@ -1,24 +1,14 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
+ * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
+ * Copyright (c) 1995-2014, The R Core Team
+ * Copyright (c) 2002-2008, The R Foundation
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates
  *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
+ * All rights reserved.
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
@@ -29,13 +19,14 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.nodes.builtin.helpers.BrowserInteractNode;
 import com.oracle.truffle.r.runtime.RBuiltin;
-import com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption;
+import com.oracle.truffle.r.runtime.RCleanUp;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RStartParams;
+import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
 import com.oracle.truffle.r.runtime.RVisibility;
-import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -43,17 +34,15 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "quit", visibility = RVisibility.OFF, kind = INTERNAL, parameterNames = {"save", "status", "runLast"})
 public abstract class Quit extends RBuiltinNode {
 
-    private static final String[] SAVE_VALUES = new String[]{"yes", "no", "ask", "default"};
-
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.toInteger(1);
     }
 
-    private void checkSaveValue(String save) throws RError {
-        for (String saveValue : SAVE_VALUES) {
+    private SA_TYPE checkSaveValue(String save) throws RError {
+        for (String saveValue : SA_TYPE.SAVE_VALUES) {
             if (saveValue.equals(save)) {
-                return;
+                return SA_TYPE.fromString(save);
             }
         }
         throw RError.error(this, RError.Message.QUIT_SAVE);
@@ -61,75 +50,34 @@ public abstract class Quit extends RBuiltinNode {
 
     @Specialization
     @TruffleBoundary
-    protected Object doQuit(RAbstractStringVector saveArg, int status, byte runLast) {
-        if (BrowserInteractNode.inBrowser()) {
+    protected Object doQuit(RAbstractStringVector saveArg, final int status, final byte runLastIn) {
+        if (RContext.getInstance().isInBrowser()) {
             RError.warning(this, RError.Message.BROWSER_QUIT);
-            return null;
+            return RNull.instance;
         }
         String save = saveArg.getDataAt(0);
-        checkSaveValue(save);
-        // Quit does not divert its output to sink
-        ConsoleHandler consoleHandler = RContext.getInstance().getConsoleHandler();
-        if (save.equals("default")) {
-            if (RContext.getInstance().getOptions().getBoolean(RCmdOption.NO_SAVE)) {
-                save = "no";
-            } else {
-                if (consoleHandler.isInteractive()) {
-                    save = "ask";
-                } else {
-                    // TODO options must be set, check
-                }
-            }
+        RStartParams.SA_TYPE ask = checkSaveValue(save);
+        if (ask == SA_TYPE.SAVEASK && !RContext.getInstance().getConsoleHandler().isInteractive()) {
+            RError.warning(this, RError.Message.QUIT_ASK_INTERACTIVE);
         }
-        boolean doSave = false;
-        if (save.equals("ask")) {
-            W: while (true) {
-                consoleHandler.setPrompt("");
-                consoleHandler.print("Save workspace image? [y/n/c]: ");
-                String response = consoleHandler.readLine();
-                if (response == null) {
-                    throw Utils.exit(status);
-                }
-                if (response.length() == 0) {
-                    continue;
-                }
-                switch (response.charAt(0)) {
-                    case 'c':
-                        consoleHandler.setPrompt("> ");
-                        return RNull.instance;
-                    case 'y':
-                        doSave = true;
-                        break W;
-                    case 'n':
-                        doSave = false;
-                        break W;
-                    default:
-                        continue;
-                }
-            }
-        }
-
-        if (doSave) {
-            /*
-             * we do not have an efficient way to tell if the global environment is "dirty", so we
-             * save always
-             */
-            RContext.getEngine().checkAndRunStartupShutdownFunction("sys.save.image", new String[]{"\".RData\""});
-            RContext.getInstance().getConsoleHandler().flushHistory();
+        if (status == RRuntime.INT_NA) {
+            RError.warning(this, RError.Message.QUIT_INVALID_STATUS);
         }
-        if (runLast != 0) {
-            RContext.getEngine().checkAndRunStartupShutdownFunction(".Last");
-            // TODO errors should return to prompt if interactive
-            RContext.getEngine().checkAndRunStartupShutdownFunction(".Last.sys");
+        byte runLast = runLastIn;
+        if (runLast == RRuntime.LOGICAL_NA) {
+            RError.warning(this, RError.Message.QUIT_INVALID_RUNLAST);
+            runLast = RRuntime.LOGICAL_FALSE;
         }
-        // destroy the context inside exit() method as it still needs to access it
-        Utils.exit(status);
-        return null;
+        RCleanUp.cleanUp(ask, status, RRuntime.fromLogical(runLast));
+        throw RInternalError.shouldNotReachHere("cleanup returned");
     }
 
     @SuppressWarnings("unused")
     @Fallback
     protected Object doQuit(Object saveArg, Object status, Object runLast) {
+        if (RRuntime.asString(saveArg) == null) {
+            throw RError.error(this, RError.Message.QUIT_ASK);
+        }
         throw RError.error(this, RError.Message.INVALID_OR_UNIMPLEMENTED_ARGUMENTS);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccf6bb98a9b6389ab65dfc261ab3c72e309a30a1
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base;
+
+import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL;
+
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.runtime.RBuiltin;
+import com.oracle.truffle.r.runtime.data.RNull;
+
+@RBuiltin(name = "setTimeLimit", kind = INTERNAL, parameterNames = {"cpu", "elapsed", "transient"})
+public abstract class SetTimeLimit extends RBuiltinNode {
+
+    @SuppressWarnings("unused")
+    @Specialization
+    protected RNull setTimeLimit(Object cpu, Object elapsed, Object trans) {
+        // TODO: proper implementation sets timers checked during user interrupts that we currently
+        // do not support
+        return RNull.instance;
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.java
index e0967508cf19f92f8a2506d5b98b19300990023e..8267a5483b7a4a4876f8387a16fc6b357560e8c0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.java
@@ -28,12 +28,13 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RBuiltin;
 import com.oracle.truffle.r.runtime.TempPathName;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
 
 @RBuiltin(name = "tempdir", kind = INTERNAL, parameterNames = {})
 public abstract class TempDir extends RBuiltinNode {
 
     @Specialization
     protected Object tempdir() {
-        return TempPathName.tempDirPath();
+        return RDataFactory.createStringVectorFromScalar(TempPathName.tempDirPath());
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
index 1ab569f1c1e1f4c16872ec4dd63a9e8b04dd4208..4b0c19acfa1957c7c6223289e284df24d963a39c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
@@ -59,6 +59,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 /**
  * The {@code vapply} builtin. The closure definition for {@code vapply} is
@@ -79,6 +80,7 @@ public abstract class VApply extends RBuiltinNode {
     private final ConditionProfile dimsProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile errorProfile = BranchProfile.create();
     private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    private final NACheck naCheck = NACheck.create();
 
     @Child private LapplyInternalNode doApply = LapplyInternalNodeGen.create();
 
@@ -156,22 +158,23 @@ public abstract class VApply extends RBuiltinNode {
         RVector result = null;
         boolean applyResultZeroLength = applyResult.length == 0;
 
+        naCheck.enable(true);
         // TODO check funValueLen against length of result
         if (funValueVec instanceof RAbstractIntVector) {
             int[] data = applyResultZeroLength ? new int[0] : convertIntVector(applyResult, funValueVecLen);
-            result = RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR);
+            result = RDataFactory.createIntVector(data, naCheck.neverSeenNA());
         } else if (funValueVec instanceof RAbstractDoubleVector) {
             double[] data = applyResultZeroLength ? new double[0] : convertDoubleVector(applyResult, funValueVecLen);
-            result = RDataFactory.createDoubleVector(data, RDataFactory.COMPLETE_VECTOR);
+            result = RDataFactory.createDoubleVector(data, naCheck.neverSeenNA());
         } else if (funValueVec instanceof RAbstractLogicalVector) {
             byte[] data = applyResultZeroLength ? new byte[0] : convertLogicalVector(applyResult, funValueVecLen);
-            result = RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR);
+            result = RDataFactory.createLogicalVector(data, naCheck.neverSeenNA());
         } else if (funValueVec instanceof RAbstractStringVector) {
             String[] data = applyResultZeroLength ? new String[0] : convertStringVector(applyResult, funValueVecLen);
-            result = RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR);
+            result = RDataFactory.createStringVector(data, naCheck.neverSeenNA());
         } else if (funValueVec instanceof RAbstractComplexVector) {
             double[] data = applyResultZeroLength ? new double[1] : convertComplexVector(applyResult, funValueVecLen);
-            result = RDataFactory.createComplexVector(data, RDataFactory.COMPLETE_VECTOR);
+            result = RDataFactory.createComplexVector(data, naCheck.neverSeenNA());
         } else {
             throw RInternalError.shouldNotReachHere();
         }
@@ -202,7 +205,9 @@ public abstract class VApply extends RBuiltinNode {
         for (int i = 0; i < values.length; i++) {
             RAbstractDoubleVector v = (RAbstractDoubleVector) RRuntime.asAbstractVector(castDouble(values[i], false));
             for (int j = 0; j < v.getLength(); j++) {
-                newArray[ind++] = v.getDataAt(j);
+                double val = v.getDataAt(j);
+                naCheck.check(val);
+                newArray[ind++] = val;
             }
         }
         return newArray;
@@ -214,7 +219,9 @@ public abstract class VApply extends RBuiltinNode {
         for (int i = 0; i < values.length; i++) {
             RAbstractIntVector v = (RAbstractIntVector) RRuntime.asAbstractVector(castInteger(values[i], false));
             for (int j = 0; j < v.getLength(); j++) {
-                newArray[ind++] = v.getDataAt(j);
+                int val = v.getDataAt(j);
+                naCheck.check(val);
+                newArray[ind++] = val;
             }
         }
         return newArray;
@@ -226,7 +233,9 @@ public abstract class VApply extends RBuiltinNode {
         for (int i = 0; i < values.length; i++) {
             RAbstractLogicalVector v = (RAbstractLogicalVector) RRuntime.asAbstractVector(castLogical(values[i], false));
             for (int j = 0; j < v.getLength(); j++) {
-                newArray[ind++] = v.getDataAt(j);
+                byte val = v.getDataAt(j);
+                naCheck.check(val);
+                newArray[ind++] = val;
             }
         }
         return newArray;
@@ -238,7 +247,9 @@ public abstract class VApply extends RBuiltinNode {
         for (int i = 0; i < values.length; i++) {
             RAbstractStringVector v = (RAbstractStringVector) RRuntime.asAbstractVector(castString(values[i], false));
             for (int j = 0; j < v.getLength(); j++) {
-                newArray[ind++] = v.getDataAt(j);
+                String val = v.getDataAt(j);
+                naCheck.check(val);
+                newArray[ind++] = val;
             }
         }
         return newArray;
@@ -251,6 +262,7 @@ public abstract class VApply extends RBuiltinNode {
             RAbstractComplexVector v = (RAbstractComplexVector) RRuntime.asAbstractVector(castComplex(values[i], false));
             for (int j = 0; j < v.getLength(); j++) {
                 RComplex val = v.getDataAt(j);
+                naCheck.check(val);
                 newArray[ind++] = val.getRealPart();
                 newArray[ind++] = val.getImaginaryPart();
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
index c0ec1fa2a2ba4fc2c375c0cb89e8c5648c292a52..254f38f888f38bac9ccc5845d39b9123a8c86b9e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
@@ -60,6 +60,7 @@ import com.oracle.truffle.r.library.utils.CountFields;
 import com.oracle.truffle.r.library.utils.Crc64NodeGen;
 import com.oracle.truffle.r.library.utils.Download;
 import com.oracle.truffle.r.library.utils.MenuNodeGen;
+import com.oracle.truffle.r.library.utils.ObjectSizeNodeGen;
 import com.oracle.truffle.r.library.utils.RprofNodeGen;
 import com.oracle.truffle.r.library.utils.TypeConvertNodeGen;
 import com.oracle.truffle.r.library.utils.WriteTable;
@@ -475,7 +476,9 @@ public class ForeignFunctions {
                 case "menu":
                     return MenuNodeGen.create();
                 case "nsl":
+                    return new UnimplementedExternal(name);
                 case "objectSize":
+                    return ObjectSizeNodeGen.create();
                 case "processevents":
                 case "octsize":
                 case "sockconnect":
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 b267e8713b6998709e7626fa3859e821d76bde3a..715197077b669b86298e6cb8a764943bb7521559 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
@@ -39,6 +39,7 @@ import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RVisibility;
 import com.oracle.truffle.r.runtime.conn.StdConnections;
@@ -69,8 +70,8 @@ public class FastRContext {
         protected int create(RAbstractStringVector args, RAbstractStringVector kindVec) {
             try {
                 RContext.ContextKind kind = RContext.ContextKind.valueOf(kindVec.getDataAt(0));
-                RCmdOptions options = RCmdOptions.parseArguments(Client.RSCRIPT, args.materialize().getDataCopy());
-                return ContextInfo.createDeferred(options, kind, RContext.getInstance(), RContext.getInstance().getConsoleHandler());
+                RStartParams startParams = new RStartParams(RCmdOptions.parseArguments(Client.RSCRIPT, args.materialize().getDataCopy(), false), false);
+                return ContextInfo.createDeferred(startParams, kind, RContext.getInstance(), RContext.getInstance().getConsoleHandler());
             } catch (IllegalArgumentException ex) {
                 throw RError.error(this, RError.Message.GENERIC, "invalid kind argument");
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
index c4f432f76388658d0dd2e37113d4b1f8f2966e8f..a3b8d6ddf73aa0f092fc42ed659e1cde2ab1d9b7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
@@ -25,7 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.fastr;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.runtime.BrowserQuitException;
+import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RBuiltin;
 import com.oracle.truffle.r.runtime.RBuiltinKind;
 import com.oracle.truffle.r.runtime.RError;
@@ -55,7 +55,7 @@ public abstract class FastRThrowIt extends RBuiltinNode {
                 throw new Utils.DebugExitException();
             case "Q":
             case "BRQ":
-                throw new BrowserQuitException();
+                throw new JumpToTopLevelException();
             default:
                 throw RError.error(this, RError.Message.GENERIC, "unknown case: " + name);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
index 5534c5b861619ba884e708bda29cf06c25493237..d88a058041e5dc99e68ddf349047e9aa9e70747e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
@@ -26,8 +26,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.base.Quit;
-import com.oracle.truffle.r.runtime.BrowserQuitException;
+import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
@@ -59,16 +58,6 @@ public abstract class BrowserInteractNode extends RNode {
 
     private static String lastEmptyLineCommand = "n";
 
-    /**
-     * This used by {@link Quit} to prevent a "quit" from the browser (as per GnuR). If we supported
-     * multiple interactive contexts, this would need become context specific.
-     */
-    private static boolean inBrowser;
-
-    public static boolean inBrowser() {
-        return inBrowser;
-    }
-
     @Specialization
     protected int interact(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreter();
@@ -78,7 +67,7 @@ public abstract class BrowserInteractNode extends RNode {
         ch.setPrompt(browserPrompt(RArguments.getDepth(frame)));
         int exitMode = NEXT;
         try {
-            inBrowser = true;
+            RContext.getInstance().setInBrowser(true);
             LW: while (true) {
                 String input = ch.readLine();
                 if (input != null) {
@@ -107,7 +96,7 @@ public abstract class BrowserInteractNode extends RNode {
                         exitMode = FINISH;
                         break LW;
                     case "Q":
-                        throw new BrowserQuitException();
+                        throw new JumpToTopLevelException();
                     case "where": {
                         if (RArguments.getDepth(mFrame) > 1) {
                             Object stack = Utils.createTraceback(0);
@@ -139,7 +128,7 @@ public abstract class BrowserInteractNode extends RNode {
             }
         } finally {
             ch.setPrompt(savedPrompt);
-            inBrowser = false;
+            RContext.getInstance().setInBrowser(false);
         }
         return exitMode;
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java
index 798fd225d0eb4101e79b8ed1b90b3722c0577653..49eb4e95d80c27d4a46bcb8a641ce011bb515e4d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java
@@ -267,7 +267,7 @@ public class TraceHandling {
             try {
                 fileWriter = new FileWriter("fastr_tracecalls.log");
             } catch (IOException e) {
-                Utils.fatalError("failed to open 'fastr_tracecalls.log'" + e.getMessage());
+                Utils.rSuicide("failed to open 'fastr_tracecalls.log'" + e.getMessage());
             }
         }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
index 12ed5ae1d2b8847c7b778bd823cf15413bfc972f..88bbd03245bbbc485a22a0394c04c525e3c5ad63 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
@@ -221,7 +221,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         int replacementLength = positionsCheckNode.getSelectedPositionsCount(positionProfiles);
         if (emptyReplacementProfile.profile(replacementLength == 0)) {
             /* Nothing to modify */
-            return vector;
+            return vector.materialize();
         }
 
         if (valueLengthOneProfile.profile(valueLength != 1)) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
index 9e3d611808fd439720b539a5e27f79e9e7889082..7918968e9b44a954492ae3e5f2a5c49020c397ff 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
@@ -48,7 +48,7 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinFactory;
 import com.oracle.truffle.r.nodes.control.BreakException;
 import com.oracle.truffle.r.nodes.control.NextException;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
-import com.oracle.truffle.r.runtime.BrowserQuitException;
+import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RArguments.DispatchArgs;
 import com.oracle.truffle.r.runtime.RArguments.S3Args;
@@ -266,7 +266,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         } catch (RError e) {
             CompilerDirectives.transferToInterpreter();
             throw e;
-        } catch (DebugExitException | BrowserQuitException | ThreadDeath e) {
+        } catch (DebugExitException | JumpToTopLevelException | ThreadDeath e) {
             /*
              * These relate to the debugging support. exitHandlers must be suppressed and the
              * exceptions must pass through unchanged; they are not errors
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index c0d41f4adfcf8089892e0b5478c73c27a15e60c0..4b501f181d8dcbc2686992ef040bf030c116d155 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -620,11 +620,21 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         state.setAsLangType();
         state.serializeNodeSetCar(getFunctionNode());
         if (isColon(getFunctionNode())) {
-            // special case, have to translate Strings to Symbols
+            // special case, have to translate Identifier names to Symbols
+            RSyntaxNode arg0 = arguments[0];
+            RSyntaxNode arg1 = arguments[1];
             state.openPairList();
-            state.setCarAsSymbol(((ReadVariableNode) arguments[0]).getIdentifier());
+            if (arg0 instanceof ReadVariableNode) {
+                state.setCarAsSymbol(((ReadVariableNode) arg0).getIdentifier());
+            } else {
+                state.setCar(((ConstantNode) arg0).getValue());
+            }
             state.openPairList();
-            state.setCarAsSymbol(((ReadVariableNode) arguments[1]).getIdentifier());
+            if (arg1 instanceof ReadVariableNode) {
+                state.setCarAsSymbol(((ReadVariableNode) arg1).getIdentifier());
+            } else {
+                state.setCar(((ConstantNode) arg1).getValue());
+            }
             state.linkPairList(2);
             state.setCdr(state.closePairList());
         } else {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
index c51da1dd105e9f7cda7fddaa74322a28564fa41c..25bf947a8304aebda46b083aa8fe12e93397d044 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
@@ -117,7 +117,7 @@ public class RInstrumentation {
             FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
             for (String debugFunctionName : debugFunctionNames) {
                 if (debugFunctionName.equals(fdn.toString())) {
-                    RContext.getRRuntimeASTAccess().enableDebug(func);
+                    RContext.getRRuntimeASTAccess().enableDebug(func, false);
                 }
             }
         }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
index ea8c579410fb0ec9c732ed0d1357ad3e402800c5..94bb5bd7e0b00f77fe845dd6eddd3d25688e3cc0 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
@@ -22,51 +22,182 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.file.Path;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.FastROptions;
+import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 
+/**
+ * Mostly support for tracing R FFI up/down calls. Currently tracing of the arguments to calls is
+ * limited. The type of the argument is printed as is the value for types with simple (short)
+ * values. Potentially complex types, e.g, {@link RPairList} do not have their values printed.
+ *
+ * Embedded mode requires special treatment. Experimentally the primary embedding app, RStudio, sets
+ * a very constrained environment (i.e. does not propagate environment variables set in the shell
+ * that launches RStudio.) and sets the cwd to "/", which is not writeable.
+ *
+ */
 public class RFFIUtils {
-    public static byte[] wrapChar(char v) {
-        return new byte[]{(byte) v};
+    private static boolean initialized;
+    /**
+     * Set this to {@code true} when it is not possible to set {@link FastROptions}.
+     */
+    private static boolean alwaysTrace;
+    /**
+     * Is set by initialization and caches whether we are tracing.
+     */
+    private static boolean traceEnabled;
+
+    /**
+     * Always trace to a file because stdout is problematic for embedded mode.
+     */
+    private static final String TRACEFILE = "fastr_trace_nativecalls.log";
+    private static FileOutputStream traceStream;
+    /**
+     * Records the call depth. TBD: make context specific
+     */
+    private static int depth;
+
+    public static void initialize() {
+        if (!initialized) {
+            traceEnabled = alwaysTrace || FastROptions.TraceNativeCalls.getBooleanValue();
+            if (traceEnabled) {
+                if (traceStream == null) {
+                    initTraceStream();
+                }
+            }
+            initialized = true;
+        }
     }
 
-    public static int[] wrapInt(int v) {
-        return new int[]{v};
+    private static void initTraceStream() {
+        Path tracePath = Utils.getLogPath(TRACEFILE);
+        try {
+            traceStream = new FileOutputStream(tracePath.toString());
+        } catch (IOException ex) {
+            System.err.println(ex.getMessage());
+            System.exit(1);
+        }
     }
 
-    public static double[] wrapDouble(double v) {
-        return new double[]{v};
+    /**
+     * Upcalled from native when tracing to get FD of the {@link #traceStream}. Allows the same fd
+     * to be used on both sides of the JNI boundary.
+     */
+    @SuppressWarnings("unused")
+    private static FileDescriptor getTraceFileDescriptor() {
+        try {
+            if (traceStream == null) {
+                // Happens if native has tracing enabled and Java does not
+                initTraceStream();
+            }
+            return traceStream.getFD();
+        } catch (IOException ex) {
+            System.err.println(ex.getMessage());
+            System.exit(1);
+            return null;
+        }
     }
 
-    @TruffleBoundary
-    public static IOException ioex(String errMsg) throws IOException {
-        throw new IOException(errMsg);
+    private enum CallMode {
+        UP("U"),
+        UP_RETURN("UR"),
+        DOWN("D"),
+        DOWN_RETURN("DR");
+
+        private final String printName;
+
+        CallMode(String printName) {
+            this.printName = printName;
+        }
+    }
+
+    public static void traceUpCall(String name, Object... args) {
+        traceCall(CallMode.UP, name, depth, args);
     }
 
-    public static void traceCall(String name, Object... args) {
-        if (FastROptions.TraceNativeCalls.getBooleanValue()) {
-            System.out.print("CallRFFI " + name + ": ");
-            printArgs(args);
-            System.out.println();
+    public static void traceUpCallReturn(String name, Object result) {
+        traceCall(CallMode.UP_RETURN, name, depth, result);
+    }
+
+    public static void traceDownCall(String name, Object... args) {
+        traceCall(CallMode.DOWN, name, ++depth, args);
+    }
+
+    public static void traceDownCallReturn(String name, Object result) {
+        traceCall(CallMode.DOWN_RETURN, name, depth--, result);
+    }
+
+    public static boolean traceEnabled() {
+        return traceEnabled;
+    }
+
+    private static void traceCall(CallMode mode, String name, int depthValue, Object... args) {
+        assert initialized;
+        if (traceEnabled) {
+            StringBuffer sb = new StringBuffer();
+            sb.append("CallRFFI[");
+            sb.append(mode.printName);
+            sb.append(':');
+            sb.append(depthValue);
+            sb.append(']');
+            sb.append(name);
+            sb.append('(');
+            printArgs(sb, args);
+            sb.append(')');
+            try {
+                traceStream.write(sb.toString().getBytes());
+                traceStream.write('\n');
+                traceStream.flush();
+            } catch (IOException ex) {
+                // ignore
+            }
         }
     }
 
-    private static void printArgs(Object[] args) {
+    private static void printArgs(StringBuffer sb, Object[] args) {
+        boolean first = true;
         for (Object arg : args) {
-            System.out.print(" ");
-            System.out.print(arg == null ? "" : arg.getClass().getSimpleName());
-            if (arg instanceof RPairList) {
-                System.out.print("[");
-                printArgs(((RPairList) arg).toRList().getDataCopy());
-                System.out.print("]");
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            sb.append(arg == null ? "" : arg.getClass().getSimpleName());
+            if (arg instanceof RSymbol) {
+                RSymbol symbol = (RSymbol) arg;
+                sb.append("(\"" + symbol.getName() + "\")");
             }
             if (!(arg instanceof RTypedValue)) {
-                System.out.print("(" + arg + ")");
+                sb.append("(" + arg + ")");
             }
         }
     }
+
+    // Miscellaneous support functions
+
+    public static byte[] wrapChar(char v) {
+        return new byte[]{(byte) v};
+    }
+
+    public static int[] wrapInt(int v) {
+        return new int[]{v};
+    }
+
+    public static double[] wrapDouble(double v) {
+        return new double[]{v};
+    }
+
+    @TruffleBoundary
+    public static IOException ioex(String errMsg) throws IOException {
+        throw new IOException(errMsg);
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
index db41c4c438d9bf67570cc3bdb114837bc654493d..de33418f4c6c31fd5e0d0a6c671d783a7b3ebb6c 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java
@@ -23,16 +23,29 @@
 package com.oracle.truffle.r.runtime.ffi.jnr;
 
 import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.frame.Frame;
+import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.RCleanUp;
+import com.oracle.truffle.r.runtime.RDeparse;
+import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RErrorHandling;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RSrcref;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
@@ -66,6 +79,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
+import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
 import com.oracle.truffle.r.runtime.rng.RRNG;
@@ -104,7 +118,7 @@ public class CallRFFIHelper {
     }
 
     private static RuntimeException unimplemented(String message) {
-        System.out.println(message);
+        System.err.println(message);
         try {
             throw RInternalError.unimplemented(message);
         } catch (Error e) {
@@ -140,23 +154,38 @@ public class CallRFFIHelper {
     // Checkstyle: stop method name check
 
     public static RIntVector Rf_ScalarInteger(int value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
+        }
         return RDataFactory.createIntVectorFromScalar(value);
     }
 
     public static RLogicalVector Rf_ScalarLogical(int value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
+        }
         return RDataFactory.createLogicalVectorFromScalar(value != 0);
     }
 
     public static RDoubleVector Rf_ScalarDouble(double value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
+        }
         return RDataFactory.createDoubleVectorFromScalar(value);
     }
 
     public static RStringVector Rf_ScalarString(Object value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarString", value);
+        }
         CharSXPWrapper chars = guaranteeInstanceOf(value, CharSXPWrapper.class);
         return RDataFactory.createStringVectorFromScalar(chars.getContents());
     }
 
     public static int Rf_asInteger(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asInteger", x);
+        }
         if (x instanceof Integer) {
             return ((Integer) x).intValue();
         } else if (x instanceof Double) {
@@ -170,6 +199,9 @@ public class CallRFFIHelper {
     }
 
     public static double Rf_asReal(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asReal", x);
+        }
         if (x instanceof Double) {
             return ((Double) x).doubleValue();
         } else if (x instanceof Byte) {
@@ -181,6 +213,9 @@ public class CallRFFIHelper {
     }
 
     public static int Rf_asLogical(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asLogical", x);
+        }
         if (x instanceof Byte) {
             return ((Byte) x).intValue();
         } else {
@@ -190,6 +225,9 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_asChar(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asChar", x);
+        }
         if (x instanceof CharSXPWrapper) {
             return x;
         } else if (x instanceof RSymbol) {
@@ -212,15 +250,24 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_mkCharLenCE(byte[] bytes, @SuppressWarnings("unused") int encoding) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
+        }
         // TODO: handle encoding properly
         return new CharSXPWrapper(new String(bytes, StandardCharsets.UTF_8));
     }
 
     public static Object Rf_cons(Object car, Object cdr) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_cons", car, cdr);
+        }
         return RDataFactory.createPairList(car, cdr);
     }
 
     public static void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
+        }
         REnvironment env = (REnvironment) envArg;
         RSymbol name = (RSymbol) symbolArg;
         try {
@@ -236,15 +283,30 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_findVar(Object symbolArg, Object envArg) {
-        return findVarInFrameHelper(symbolArg, envArg, true);
+        // WARNING: argument order reversed from Rf_findVarInFrame!
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
+        }
+        return findVarInFrameHelper(envArg, symbolArg, true);
     }
 
     public static Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
-        // important: this functions does have a different signature than findVar
-        return findVarInFrameHelper(symbolArg, envArg, false);
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findVarInFrame", envArg, symbolArg);
+        }
+        return findVarInFrameHelper(envArg, symbolArg, false);
     }
 
-    private static Object findVarInFrameHelper(Object symbolArg, Object envArg, boolean inherits) {
+    public static Object Rf_findVarInFrame3(Object envArg, Object symbolArg, @SuppressWarnings("unused") int doGet) {
+        // GNU R has code for IS_USER_DATBASE that uses doGet
+        // This is a lookup in the single environment (envArg) only, i.e. inherits=false
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
+        }
+        return findVarInFrameHelper(envArg, symbolArg, false);
+    }
+
+    private static Object findVarInFrameHelper(Object envArg, Object symbolArg, boolean inherits) {
         if (envArg == RNull.instance) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.USE_NULL_ENV_DEFUNCT);
         }
@@ -259,6 +321,7 @@ public class CallRFFIHelper {
                 return value;
             }
             if (!inherits) {
+                // simgle frame lookup
                 break;
             }
             env = env.getParent();
@@ -267,6 +330,9 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_getAttrib(Object obj, Object name) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
+        }
         Object result = RNull.instance;
         if (obj instanceof RAttributable) {
             RAttributable attrObj = (RAttributable) obj;
@@ -283,6 +349,9 @@ public class CallRFFIHelper {
     }
 
     public static void Rf_setAttrib(Object obj, Object name, Object val) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_setAttrib", obj, name);
+        }
         if (obj instanceof RAttributable) {
             RAttributable attrObj = (RAttributable) obj;
             String nameAsString;
@@ -303,51 +372,69 @@ public class CallRFFIHelper {
         }
     }
 
-    public static RStringVector getClassHr(Object v) {
+    private static RStringVector getClassHr(Object v) {
+        RStringVector result;
         if (v instanceof RAttributable) {
-            return ((RAttributable) v).getClassHierarchy();
+            result = ((RAttributable) v).getClassHierarchy();
         } else if (v instanceof Byte) {
-            return RLogicalVector.implicitClassHeader;
+            result = RLogicalVector.implicitClassHeader;
         } else if (v instanceof String) {
-            return RStringVector.implicitClassHeader;
+            result = RStringVector.implicitClassHeader;
         } else if (v instanceof Integer) {
-            return RIntVector.implicitClassHeader;
+            result = RIntVector.implicitClassHeader;
         } else if (v instanceof Double) {
-            return RDoubleVector.implicitClassHeader;
+            result = RDoubleVector.implicitClassHeader;
         } else if (v instanceof RComplex) {
-            return RComplexVector.implicitClassHeader;
+            result = RComplexVector.implicitClassHeader;
         } else if (v instanceof RRaw) {
-            return RRawVector.implicitClassHeader;
+            result = RRawVector.implicitClassHeader;
         } else {
             guaranteeInstanceOf(v, RNull.class);
-            return RNull.implicitClassHeader;
+            result = RNull.implicitClassHeader;
         }
+        return result;
     }
 
     public static int Rf_inherits(Object x, String clazz) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
+        }
+        int result = 0;
         RStringVector hierarchy = getClassHr(x);
         for (int i = 0; i < hierarchy.getLength(); i++) {
             if (hierarchy.getDataAt(i).equals(clazz)) {
-                return 1;
+                result = 1;
             }
         }
-        return 0;
+        return result;
     }
 
     public static Object Rf_lengthgets(Object x, int newSize) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
+        }
         RAbstractVector vec = (RAbstractVector) RRuntime.asAbstractVector(x);
         return vec.resize(newSize);
     }
 
     public static int Rf_isString(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_isString", x);
+        }
         return RRuntime.checkType(x, RType.Character) ? 1 : 0;
     }
 
     public static int Rf_isNull(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_isNull", x);
+        }
         return x == RNull.instance ? 1 : 0;
     }
 
     public static Object Rf_PairToVectorList(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
+        }
         if (x == RNull.instance) {
             return RDataFactory.createList();
         }
@@ -356,18 +443,30 @@ public class CallRFFIHelper {
     }
 
     public static void Rf_error(String msg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_error", msg);
+        }
         throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
     public static void Rf_warning(String msg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_warning", msg);
+        }
         RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
     public static void Rf_warningcall(Object call, String msg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
+        }
         RErrorHandling.warningcallRFFI(call, msg);
     }
 
     public static Object Rf_allocateVector(int mode, int n) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
+        }
         SEXPTYPE type = SEXPTYPE.mapInt(mode);
         if (n < 0) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
@@ -388,12 +487,17 @@ public class CallRFFIHelper {
                 return RDataFactory.createRawVector(new byte[n]);
             case VECSXP:
                 return RDataFactory.createList(n);
+            case LANGSXP:
+                return RDataFactory.createLangPairList(n);
             default:
                 throw unimplemented("unexpected SEXPTYPE " + type);
         }
     }
 
     public static Object Rf_allocateArray(int mode, Object dimsObj) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
+        }
         RIntVector dims = (RIntVector) dimsObj;
         int n = 1;
         int[] newDims = new int[dims.getLength()];
@@ -409,6 +513,9 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_allocateMatrix(int mode, int ncol, int nrow) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
+        }
         SEXPTYPE type = SEXPTYPE.mapInt(mode);
         if (nrow < 0 || ncol < 0) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_EXTENTS_TO_MATRIX);
@@ -432,6 +539,9 @@ public class CallRFFIHelper {
     }
 
     public static int LENGTH(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("LENGTH", x);
+        }
         if (x instanceof RAbstractContainer) {
             return ((RAbstractContainer) x).getLength();
         } else if (x == RNull.instance) {
@@ -446,17 +556,26 @@ public class CallRFFIHelper {
     }
 
     public static void SET_STRING_ELT(Object x, int i, Object v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
+        }
         RStringVector vector = guaranteeInstanceOf(x, RStringVector.class);
         CharSXPWrapper element = guaranteeInstanceOf(v, CharSXPWrapper.class);
         vector.setElement(i, element.getContents());
     }
 
     public static void SET_VECTOR_ELT(Object x, int i, Object v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
+        }
         RList list = guaranteeInstanceOf(x, RList.class);
         list.setElement(i, v);
     }
 
     public static byte[] RAW(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("RAW", x);
+        }
         if (x instanceof RRawVector) {
             return ((RRawVector) x).getDataWithoutCopying();
         } else if (x instanceof RRaw) {
@@ -467,6 +586,9 @@ public class CallRFFIHelper {
     }
 
     public static byte[] LOGICAL(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("LOGICAL", x);
+        }
         if (x instanceof RLogicalVector) {
             return ((RLogicalVector) x).getDataWithoutCopying();
         } else if (x instanceof Byte) {
@@ -477,6 +599,9 @@ public class CallRFFIHelper {
     }
 
     public static int[] INTEGER(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("INTEGER", x);
+        }
         if (x instanceof RIntVector) {
             return ((RIntVector) x).getDataWithoutCopying();
         } else if (x instanceof RIntSequence) {
@@ -497,6 +622,9 @@ public class CallRFFIHelper {
     }
 
     public static double[] REAL(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("REAL", x);
+        }
         if (x instanceof RDoubleVector) {
             return ((RDoubleVector) x).getDataWithoutCopying();
         } else if (x instanceof RDoubleSequence) {
@@ -513,17 +641,29 @@ public class CallRFFIHelper {
     }
 
     public static Object STRING_ELT(Object x, int i) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("STRING_ELT", x, i);
+        }
         RAbstractStringVector vector = guaranteeInstanceOf(RRuntime.asAbstractVector(x), RAbstractStringVector.class);
         return new CharSXPWrapper(vector.getDataAt(i));
     }
 
     public static Object VECTOR_ELT(Object x, int i) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
+        }
         Object vec = x;
+        if (vec instanceof RExpression) {
+            return ((RExpression) vec).getDataAt(i);
+        }
         RAbstractListVector list = guaranteeInstanceOf(RRuntime.asAbstractVector(vec), RAbstractListVector.class);
         return list.getDataAt(i);
     }
 
     public static int NAMED(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("NAMED", x);
+        }
         if (x instanceof RShareable) {
             return ((RShareable) x).isShared() ? 1 : 0;
         } else {
@@ -532,6 +672,9 @@ public class CallRFFIHelper {
     }
 
     public static Object SET_TYPEOF_FASTR(Object x, int v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
+        }
         int code = SEXPTYPE.gnuRCodeForObject(x);
         if (code == SEXPTYPE.LISTSXP.code && v == SEXPTYPE.LANGSXP.code) {
             RList l;
@@ -547,6 +690,9 @@ public class CallRFFIHelper {
     }
 
     public static int TYPEOF(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("TYPEOF", x);
+        }
         if (x instanceof CharSXPWrapper) {
             return SEXPTYPE.CHARSXP.code;
         } else {
@@ -555,6 +701,9 @@ public class CallRFFIHelper {
     }
 
     public static int OBJECT(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("OBJECT", x);
+        }
         if (x instanceof RAttributable) {
             return ((RAttributable) x).getAttr(RRuntime.CLASS_ATTR_KEY) == null ? 0 : 1;
         } else {
@@ -563,11 +712,17 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_duplicate(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_duplicate", x);
+        }
         guaranteeInstanceOf(x, RAbstractVector.class);
         return ((RAbstractVector) x).copy();
     }
 
     public static int Rf_anyDuplicated(Object x, int fromLast) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
+        }
         RAbstractVector vec = (RAbstractVector) x;
         if (vec.getLength() == 0) {
             return 0;
@@ -577,11 +732,17 @@ public class CallRFFIHelper {
     }
 
     public static Object PRINTNAME(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("PRINTNAME", x);
+        }
         guaranteeInstanceOf(x, RSymbol.class);
         return new CharSXPWrapper(((RSymbol) x).getName());
     }
 
     public static Object TAG(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("TAG", e);
+        }
         if (e instanceof RPairList) {
             return ((RPairList) e).getTag();
         } else {
@@ -592,11 +753,21 @@ public class CallRFFIHelper {
     }
 
     public static Object CAR(Object e) {
-        guaranteeInstanceOf(e, RPairList.class);
-        return ((RPairList) e).car();
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CAR", e);
+        }
+        guarantee(e != null && (RPairList.class.isInstance(e) || RLanguage.class.isInstance(e)), "CAR only works on pair lists and language objects");
+        if (e instanceof RPairList) {
+            return ((RPairList) e).car();
+        } else {
+            return ((RLanguage) e).getDataAtAsObject(0);
+        }
     }
 
     public static Object CDR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CDR", e);
+        }
         if (e instanceof RLanguage) {
             RLanguage lang = (RLanguage) e;
             int length = RContext.getRRuntimeASTAccess().getLength(lang);
@@ -615,7 +786,22 @@ public class CallRFFIHelper {
         }
     }
 
+    public static Object CADR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CADR", e);
+        }
+        guarantee(e != null && (RPairList.class.isInstance(e) || RLanguage.class.isInstance(e)), "CADR only works on pair lists and language objects");
+        if (e instanceof RPairList) {
+            return ((RPairList) e).cadr();
+        } else {
+            return ((RLanguage) e).getDataAtAsObject(1);
+        }
+    }
+
     public static Object CDDR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CDDR", e);
+        }
         if (e instanceof RLanguage) {
             RLanguage lang = (RLanguage) e;
             int length = RContext.getRRuntimeASTAccess().getLength(lang);
@@ -634,12 +820,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object CADR(Object e) {
-        guaranteeInstanceOf(e, RPairList.class);
-        return ((RPairList) e).cadr();
-    }
-
     public static Object SET_TAG(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_TAG", x, y);
+        }
         if (x instanceof RPairList) {
             ((RPairList) x).setTag(y);
         } else {
@@ -651,23 +835,95 @@ public class CallRFFIHelper {
     }
 
     public static Object SETCAR(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SETCAR", x, y);
+        }
         guaranteeInstanceOf(x, RPairList.class);
         ((RPairList) x).setCar(y);
         return x; // TODO check or y?
     }
 
     public static Object SETCDR(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SETCDR", x, y);
+        }
         guaranteeInstanceOf(x, RPairList.class);
         ((RPairList) x).setCdr(y);
         return x; // TODO check or y?
     }
 
+    public static Object SYMVALUE(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SYMVALUE", x);
+        }
+        if (!(x instanceof RSymbol)) {
+            throw RInternalError.shouldNotReachHere();
+        }
+        Object res = REnvironment.baseEnv().get(((RSymbol) x).getName());
+        if (res == null) {
+            return RUnboundValue.instance;
+        } else {
+            return res;
+        }
+    }
+
+    public static void SET_SYMVALUE(Object x, Object v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
+        }
+        if (!(x instanceof RSymbol)) {
+            throw RInternalError.shouldNotReachHere();
+        }
+        REnvironment.baseEnv().safePut(((RSymbol) x).getName(), v);
+    }
+
+    public static int R_BindingIsLocked(Object sym, Object env) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_BindingIsLocked", sym, env);
+        }
+        guaranteeInstanceOf(sym, RSymbol.class);
+        guaranteeInstanceOf(env, REnvironment.class);
+        return ((REnvironment) env).bindingIsLocked(((RSymbol) sym).getName()) ? 1 : 0;
+    }
+
     public static Object R_FindNamespace(Object name) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_FindNamespace", name);
+        }
         Object result = RContext.getInstance().stateREnvironment.getNamespaceRegistry().get(RRuntime.asString(name));
         return result;
     }
 
+    private static Object convertPairList(RPairList list) {
+        try {
+            if (list.getType() == SEXPTYPE.LANGSXP) {
+                RPairList pl = list;
+                Map<String, Object> constants = new HashMap<>();
+                String deparse = RDeparse.deparseDeserialize(constants, pl);
+                Source source = RSource.fromTextInternal(deparse, RSource.Internal.PAIRLIST_DEPARSE);
+                RExpression expr = RContext.getEngine().parse(constants, source);
+                assert expr.getLength() == 1;
+                Object result = expr.getDataAt(0);
+                RAttributes attrs = pl.getAttributes();
+                if (result instanceof RAttributable) {
+                    RAttributes.copyAttributes((RAttributable) result, attrs);
+                }
+                return result;
+
+            } else {
+                throw RInternalError.shouldNotReachHere();
+            }
+        } catch (Throwable x) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+    }
+
+    @TruffleBoundary
     public static Object Rf_eval(Object expr, Object env) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_eval", expr, env);
+        }
         guarantee(env instanceof REnvironment);
         Object result;
         if (expr instanceof RPromise) {
@@ -676,6 +932,8 @@ public class CallRFFIHelper {
             result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, RCaller.createInvalid(null));
         } else if (expr instanceof RLanguage) {
             result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, RCaller.createInvalid(null));
+        } else if (expr instanceof RPairList) {
+            result = Rf_eval(convertPairList((RPairList) expr), env);
         } else {
             // just return value
             result = expr;
@@ -684,6 +942,9 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_findfun(Object symbolObj, Object envObj) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
+        }
         guarantee(envObj instanceof REnvironment);
         REnvironment env = (REnvironment) envObj;
         guarantee(symbolObj instanceof RSymbol);
@@ -699,12 +960,18 @@ public class CallRFFIHelper {
     }
 
     public static Object Rf_GetOption1(Object tag) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_GetOption1", tag);
+        }
         guarantee(tag instanceof RSymbol);
         Object result = RContext.getInstance().stateROptions.getValue(((RSymbol) tag).getName());
         return result;
     }
 
     public static void Rf_gsetVar(Object symbol, Object value, Object rho) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
+        }
         guarantee(symbol instanceof RSymbol);
         REnvironment baseEnv = RContext.getInstance().stateREnvironment.getBaseEnv();
         guarantee(rho == baseEnv);
@@ -716,6 +983,9 @@ public class CallRFFIHelper {
     }
 
     public static void DUPLICATE_ATTRIB(Object to, Object from) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
+        }
         if (from instanceof RAttributable) {
             guaranteeInstanceOf(to, RAttributable.class);
             RAttributes attributes = ((RAttributable) from).getAttributes();
@@ -725,12 +995,18 @@ public class CallRFFIHelper {
     }
 
     public static REnvironment Rf_createNewEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_createNewEnv", parent, name, hashed, initialSize);
+        }
         REnvironment env = RDataFactory.createNewEnv(name, hashed, initialSize);
         RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
         return env;
     }
 
     public static int R_computeIdentical(Object x, Object y, int flags) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
+        }
         RFunction indenticalBuiltin = RContext.lookupBuiltin("identical");
         Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
                         RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0))));
@@ -739,41 +1015,227 @@ public class CallRFFIHelper {
 
     @SuppressWarnings("unused")
     public static void Rf_copyListMatrix(Object s, Object t, int byrow) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
+        }
         throw unimplemented();
     }
 
     @SuppressWarnings("unused")
     public static void Rf_copyMatrix(Object s, Object t, int byrow) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
+        }
         throw unimplemented();
     }
 
+    public static Object R_tryEval(Object expr, Object env, boolean silent) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
+        }
+        Object handlerStack = RErrorHandling.getHandlerStack();
+        Object restartStack = RErrorHandling.getRestartStack();
+        try {
+            // TODO handle silent
+            RErrorHandling.resetStacks();
+            Object result = Rf_eval(expr, env);
+            return result;
+        } catch (Throwable t) {
+            return null;
+        } finally {
+            RErrorHandling.restoreStacks(handlerStack, restartStack);
+        }
+    }
+
+    public static int RDEBUG(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("RDEBUG", x);
+        }
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        if (env instanceof REnvironment.Function) {
+            REnvironment.Function funcEnv = (REnvironment.Function) env;
+            RFunction func = RArguments.getFunction(funcEnv.getFrame());
+            return RContext.getRRuntimeASTAccess().isDebugged(func) ? 1 : 0;
+        } else {
+            return 0;
+        }
+    }
+
+    public static void SET_RDEBUG(Object x, int v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
+        }
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        if (env instanceof REnvironment.Function) {
+            REnvironment.Function funcEnv = (REnvironment.Function) env;
+            RFunction func = RArguments.getFunction(funcEnv.getFrame());
+            if (v == 1) {
+                RContext.getRRuntimeASTAccess().enableDebug(func, false);
+            } else {
+                RContext.getRRuntimeASTAccess().disableDebug(func);
+            }
+        }
+    }
+
+    public static int RSTEP(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("RSTEP", x);
+        }
+        @SuppressWarnings("unused")
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        throw RInternalError.unimplemented("RSTEP");
+    }
+
+    public static void SET_RSTEP(Object x, int v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_RSTEP", x, v);
+        }
+        @SuppressWarnings("unused")
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        throw RInternalError.unimplemented("SET_RSTEP");
+    }
+
+    public static Object ENCLOS(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("ENCLOS", x);
+        }
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        Object result = env.getParent();
+        if (result == null) {
+            result = RNull.instance;
+        }
+        return result;
+    }
+
+    public static Object PRVALUE(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("PRVALUE", x);
+        }
+        RPromise p = guaranteeInstanceOf(x, RPromise.class);
+        return p.isEvaluated() ? p.getValue() : RUnboundValue.instance;
+    }
+
+    private enum ParseStatus {
+        PARSE_NULL,
+        PARSE_OK,
+        PARSE_INCOMPLETE,
+        PARSE_ERROR,
+        PARSE_EOF
+    }
+
+    private static class ParseResult {
+        @SuppressWarnings("unused") private final int parseStatus;
+        @SuppressWarnings("unused") private final Object expr;
+
+        private ParseResult(int parseStatus, Object expr) {
+            this.parseStatus = parseStatus;
+            this.expr = expr;
+        }
+    }
+
+    public static Object R_ParseVector(Object text, int n, Object srcFile) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ParseVector", text, n, srcFile);
+        }
+        // TODO general case
+        assert n == 1;
+        assert srcFile == RNull.instance;
+        String textString = RRuntime.asString(text);
+        assert textString != null;
+
+        try {
+            Source source = RSource.fromTextInternal(textString, RSource.Internal.R_PARSEVECTOR);
+            RExpression exprs = RContext.getEngine().parse(null, source);
+            return new ParseResult(ParseStatus.PARSE_OK.ordinal(), exprs);
+        } catch (ParseException ex) {
+            // TODO incomplete
+            return new ParseResult(ParseStatus.PARSE_ERROR.ordinal(), RNull.instance);
+        }
+
+    }
+
+    public static Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_lsInternal3", envArg, allArg, sortedArg);
+        }
+        boolean sorted = sortedArg != 0;
+        boolean all = allArg != 0;
+        REnvironment env = guaranteeInstanceOf(envArg, REnvironment.class);
+        return env.ls(all, null, sorted);
+    }
+
+    @SuppressWarnings("unused")
+    private static String R_HomeDir() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_HomeDir");
+        }
+        return REnvVars.rHome();
+    }
+
+    @SuppressWarnings("unused")
+    private static void R_CleanUp(int sa, int status, int runlast) {
+        RCleanUp.stdCleanUp(SA_TYPE.values()[sa], status, runlast != 0);
+    }
+
     // Checkstyle: resume method name check
 
     public static Object validate(Object x) {
         return x;
     }
 
+    private static RCaller topLevel = RCaller.createInvalid(null);
+
+    public static Object getGlobalContext() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getGlobalContext");
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        if (frame == null) {
+            return topLevel;
+        }
+        RCaller rCaller = RArguments.getCall(frame);
+        return rCaller == null ? topLevel : rCaller;
+    }
+
     public static Object getGlobalEnv() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getGlobalEnv");
+        }
         return RContext.getInstance().stateREnvironment.getGlobalEnv();
     }
 
     public static Object getBaseEnv() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getBaseEnv");
+        }
         return RContext.getInstance().stateREnvironment.getBaseEnv();
     }
 
     public static Object getBaseNamespace() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getBaseNamespace");
+        }
         return RContext.getInstance().stateREnvironment.getBaseNamespace();
     }
 
     public static Object getNamespaceRegistry() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getNamespaceRegistry");
+        }
         return RContext.getInstance().stateREnvironment.getNamespaceRegistry();
     }
 
     public static int isInteractive() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("isInteractive");
+        }
         return RContext.getInstance().isInteractive() ? 1 : 0;
     }
 
     public static int isS4Object(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("isS4Object");
+        }
         return x instanceof RS4Object ? 1 : 0;
     }
 
@@ -782,14 +1244,182 @@ public class CallRFFIHelper {
     }
 
     public static void getRNGstate() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getRNGstate");
+        }
         RRNG.getRNGState();
     }
 
     public static void putRNGstate() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("putRNGstate");
+        }
         RRNG.updateDotRandomSeed();
     }
 
     public static double unifRand() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("unifRand");
+        }
         return RRNG.unifRand();
     }
+
+    // Checkstyle: stop method name check
+
+    public static Object R_getGlobalFunctionContext() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getGlobalFunctionContext");
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        if (frame == null) {
+            return RNull.instance;
+        }
+        RCaller currentCaller = RArguments.getCall(frame);
+        while (currentCaller != null) {
+            if (!currentCaller.isPromise()) {
+                break;
+            }
+            currentCaller = currentCaller.getParent();
+        }
+        return currentCaller == null ? RNull.instance : currentCaller;
+    }
+
+    public static Object R_getParentFunctionContext(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getParentFunctionContext");
+        }
+        RCaller currentCaller = guaranteeInstanceOf(c, RCaller.class);
+        while (true) {
+            currentCaller = currentCaller.getParent();
+            if (currentCaller == null || !currentCaller.isPromise()) {
+                break;
+            }
+        }
+        return currentCaller == null ? RNull.instance : currentCaller;
+    }
+
+    public static Object R_getFunctionContext(int depth) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getFunctionContext", depth);
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        RCaller currentCaller = RArguments.getCall(frame);
+        int currentDepth = 0;
+        while (currentCaller != null) {
+            if (!currentCaller.isPromise()) {
+                currentDepth++;
+                if (currentDepth >= depth) {
+                    break;
+                }
+            }
+            currentCaller = currentCaller.getParent();
+        }
+        return currentCaller == null ? RNull.instance : currentCaller;
+    }
+
+    public static Object R_getContextEnv(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getContextEnv", c);
+        }
+        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
+        if (rCaller == topLevel) {
+            return RContext.getInstance().stateREnvironment.getGlobalEnv();
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        if (RArguments.getCall(frame) == rCaller) {
+            return REnvironment.frameToEnvironment(frame.materialize());
+        } else {
+            Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
+
+                @Override
+                public Object apply(Frame f) {
+                    RCaller currentCaller = RArguments.getCall(f);
+                    if (currentCaller == rCaller) {
+                        return REnvironment.frameToEnvironment(f.materialize());
+                    } else {
+                        return null;
+                    }
+                }
+            });
+            return result;
+        }
+    }
+
+    public static Object R_getContextFun(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getContextEnv", c);
+        }
+        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
+        if (rCaller == topLevel) {
+            return RNull.instance;
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        if (RArguments.getCall(frame) == rCaller) {
+            return RArguments.getFunction(frame);
+        } else {
+            Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
+
+                @Override
+                public Object apply(Frame f) {
+                    RCaller currentCaller = RArguments.getCall(f);
+                    if (currentCaller == rCaller) {
+                        return RArguments.getFunction(f);
+                    } else {
+                        return null;
+                    }
+                }
+            });
+            return result;
+        }
+    }
+
+    public static Object R_getContextCall(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getContextEnv", c);
+        }
+        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
+        if (rCaller == topLevel) {
+            return RNull.instance;
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        if (RArguments.getCall(frame) == rCaller) {
+            return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller);
+        } else {
+            Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
+
+                @Override
+                public Object apply(Frame f) {
+                    RCaller currentCaller = RArguments.getCall(f);
+                    if (currentCaller == rCaller) {
+                        return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller);
+                    } else {
+                        return null;
+                    }
+                }
+            });
+            return result;
+        }
+    }
+
+    public static Object R_getContextSrcRef(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("getContextSrcRef", c);
+        }
+        Object o = R_getContextFun(c);
+        if (!(o instanceof RFunction)) {
+            return RNull.instance;
+        } else {
+            RFunction f = (RFunction) o;
+            SourceSection ss = f.getRootNode().getSourceSection();
+            String path = ss.getSource().getPath();
+            return RSrcref.createLloc(ss, path);
+
+        }
+
+    }
+
+    public static int R_insideBrowser() {
+        return RContext.getInstance().isInBrowser() ? 1 : 0;
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java
index ea66b457f672074f6db28973d322cab925331d48..70c2779c9081b931c2910f712446abeaa6de3022 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_CallRFFI.java
@@ -22,9 +22,9 @@
  */
 package com.oracle.truffle.r.runtime.ffi.jnr;
 
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceCall;
-
-import java.util.concurrent.Semaphore;
+import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCall;
+import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCallReturn;
+import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceEnabled;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -32,6 +32,7 @@ import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLException;
 import com.oracle.truffle.r.runtime.ffi.LibPaths;
+import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
 
 /**
@@ -66,37 +67,49 @@ public class JNI_CallRFFI implements CallRFFI {
             throw new RInternalError(ex, "error while loading " + librffiPath);
         }
         System.load(librffiPath);
-        traceCall("initialize");
-        initialize(RFFIVariables.values());
-    }
+        RFFIUtils.initialize();
+        if (traceEnabled()) {
+            traceDownCall("initialize");
+        }
+        try {
+            initialize(RFFIVariables.values());
+        } finally {
+            if (traceEnabled()) {
+                traceDownCallReturn("initialize", null);
+            }
 
-    private static final Semaphore inCritical = new Semaphore(1, false);
+        }
+    }
 
     @Override
-    public Object invokeCall(long address, String name, Object[] args) {
-        traceCall(name, args);
+    @TruffleBoundary
+    public synchronized Object invokeCall(long address, String name, Object[] args) {
+        Object result = null;
+        if (traceEnabled()) {
+            traceDownCall(name, args);
+        }
         try {
-            inCritical.acquire();
             switch (args.length) {
             // @formatter:off
-            case 0: return call0(address);
-            case 1: return call1(address, args[0]);
-            case 2: return call2(address, args[0], args[1]);
-            case 3: return call3(address, args[0], args[1], args[2]);
-            case 4: return call4(address, args[0], args[1], args[2], args[3]);
-            case 5: return call5(address, args[0], args[1], args[2], args[3], args[4]);
-            case 6: return call6(address, args[0], args[1], args[2], args[3], args[4], args[5]);
-            case 7: return call7(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
-            case 8: return call8(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
-            case 9: return call9(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
+            case 0: result = call0(address); break;
+            case 1: result = call1(address, args[0]); break;
+            case 2: result = call2(address, args[0], args[1]); break;
+            case 3: result = call3(address, args[0], args[1], args[2]); break;
+            case 4: result = call4(address, args[0], args[1], args[2], args[3]); break;
+            case 5: result = call5(address, args[0], args[1], args[2], args[3], args[4]); break;
+            case 6: result = call6(address, args[0], args[1], args[2], args[3], args[4], args[5]); break;
+            case 7: result = call7(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
+            case 8: result = call8(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
+            case 9: result = call9(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
             default:
-                return call(address, args);
+                result = call(address, args); break;
                 // @formatter:on
             }
-        } catch (InterruptedException ex) {
-            throw RInternalError.shouldNotReachHere();
+            return result;
         } finally {
-            inCritical.release();
+            if (traceEnabled()) {
+                traceDownCallReturn(name, result);
+            }
         }
     }
 
@@ -104,6 +117,8 @@ public class JNI_CallRFFI implements CallRFFI {
 
     private static native void nativeSetTempDir(String tempDir);
 
+    private static native void nativeSetInteractive(boolean interactive);
+
     private static native Object call(long address, Object[] args);
 
     private static native Object call0(long address);
@@ -127,10 +142,12 @@ public class JNI_CallRFFI implements CallRFFI {
     private static native Object call9(long address, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9);
 
     @Override
-    public void invokeVoidCall(long address, String name, Object[] args) {
-        traceCall(name, args);
+    @TruffleBoundary
+    public synchronized void invokeVoidCall(long address, String name, Object[] args) {
+        if (traceEnabled()) {
+            traceDownCall(name, args);
+        }
         try {
-            inCritical.acquire();
             switch (args.length) {
                 case 0:
                     callVoid0(address);
@@ -141,9 +158,10 @@ public class JNI_CallRFFI implements CallRFFI {
                 default:
                     throw RInternalError.shouldNotReachHere();
             }
-        } catch (InterruptedException ex) {
         } finally {
-            inCritical.release();
+            if (traceEnabled()) {
+                traceDownCallReturn(name, null);
+            }
         }
     }
 
@@ -152,15 +170,26 @@ public class JNI_CallRFFI implements CallRFFI {
     private static native void callVoid1(long address, Object arg1);
 
     @Override
-    public void setTempDir(String tempDir) {
-        traceCall("setTempDir", tempDir);
-        try {
-            inCritical.acquire();
-            RFFIVariables.setTempDir(tempDir);
-            nativeSetTempDir(tempDir);
-        } catch (InterruptedException ex) {
-        } finally {
-            inCritical.release();
+    public synchronized void setTempDir(String tempDir) {
+        if (traceEnabled()) {
+            traceDownCall("setTempDir", tempDir);
+        }
+        RFFIVariables.setTempDir(tempDir);
+        nativeSetTempDir(tempDir);
+        if (traceEnabled()) {
+            traceDownCallReturn("setTempDir", null);
         }
     }
+
+    @Override
+    public synchronized void setInteractive(boolean interactive) {
+        if (traceEnabled()) {
+            traceDownCall("setInteractive", interactive);
+        }
+        nativeSetInteractive(interactive);
+        if (traceEnabled()) {
+            traceDownCallReturn("setInteractive", null);
+        }
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_PkgInit.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_PkgInit.java
index 956a916c408daf8d554e5ee68c792daf2f13c4ff..4576a66fdf3cec66e4430969573602e730985521 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_PkgInit.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_PkgInit.java
@@ -67,4 +67,13 @@ final class JNI_PkgInit {
     public static int forceSymbols(DLLInfo dllInfo, int value) {
         return DLL.forceSymbols(dllInfo, value);
     }
+
+    public static DLLInfo getEmbeddingDllInfo() {
+        return DLL.getEmbeddingDLLInfo();
+    }
+
+    @SuppressWarnings("unused")
+    public static int findSymbol(String name, String pkg, DLL.RegisteredNativeSymbol rns) {
+        throw RInternalError.unimplemented();
+    }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_REmbed.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_REmbed.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6fe980732140e280f2c1bfdd4ded4a93d4335f4
--- /dev/null
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNI_REmbed.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi.jnr;
+
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
+
+public class JNI_REmbed implements REmbedRFFI {
+
+    @Override
+    public void suicide(String x) {
+        nativeSuicide(x);
+    }
+
+    @Override
+    public void cleanUp(int type, int x, int y) {
+        nativeCleanUp(type, x, y);
+    }
+
+    @Override
+    public String readConsole(String prompt) {
+        return nativeReadConsole(prompt);
+    }
+
+    @Override
+    public void writeConsole(String x) {
+        nativeWriteConsole(x);
+    }
+
+    @Override
+    public void writeErrConsole(String x) {
+        nativeWriteErrConsole(x);
+    }
+
+    private static native void nativeSuicide(String x);
+
+    private static native String nativeReadConsole(String prompt);
+
+    private static native void nativeWriteConsole(String x);
+
+    private static native void nativeWriteErrConsole(String x);
+
+    private static native void nativeCleanUp(int type, int x, int y);
+
+}
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
index 97976cf72db7e72971186d1b3641bece94574c99..168618a998bd8e666fe27f37136eaf78372965a4 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
 import com.oracle.truffle.r.runtime.ffi.RApplRFFI;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
@@ -58,7 +59,7 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI {
          * Some package C code calls these functions and, therefore, expects the linpack symbols to
          * be available, which will not be the case unless one of the functions has already been
          * called from R code. So we eagerly load the library to define the symbols.
-         * 
+         *
          * There is an additional problem when running without a *_LIBRARY_PATH being set which is
          * mandated by Mac OSX El Capitan, which is we must tell JNR where to find the libraries.
          */
@@ -198,4 +199,15 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI {
         }
         return pcreRFFI;
     }
+
+    private REmbedRFFI rEmbedRFFI;
+
+    @Override
+    public REmbedRFFI getREmbedRFFI() {
+        if (rEmbedRFFI == null) {
+            rEmbedRFFI = new JNI_REmbed();
+        }
+        return rEmbedRFFI;
+    }
+
 }
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 8d04af165f9ced86ced2791b37fc76261077f2eb..fb9aadcd68888f2d52dfbf0cbf6ddc9437b65fbd 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime;
 
+import java.util.Map;
 import java.util.Map.Entry;
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -164,6 +165,20 @@ public enum FastROptions {
                 }
             }
         }
+        for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
+            String name = entry.getKey();
+            if (name.startsWith("FASTR_OPTION_")) {
+                name = name.replace("FASTR_OPTION_", "");
+                String value = entry.getValue();
+                if (value == null || value.equals("true") || value.equals("")) {
+                    FastROptions.setValue(name, true);
+                } else if (value.equals("false")) {
+                    FastROptions.setValue(name, false);
+                } else {
+                    FastROptions.setValue(name, value);
+                }
+            }
+        }
         initialized = true;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/BrowserQuitException.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/JumpToTopLevelException.java
similarity index 81%
rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/BrowserQuitException.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/JumpToTopLevelException.java
index d3a28e3013b749cdefe51dce7f4cbff636285828..4435f09a33fbf6d6f7e72442bbfc15f77b2879b3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/BrowserQuitException.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/JumpToTopLevelException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -23,9 +23,10 @@
 package com.oracle.truffle.r.runtime;
 
 /**
- * Thrown in response to the "Q" command in the browser.
+ * Thrown whenever the system wants to return to the top level, e.g. "Q" in browser, "c" in the
+ * {@code quit} builtin.
  */
-public class BrowserQuitException extends RuntimeException {
+public class JumpToTopLevelException extends RuntimeException {
 
     private static final long serialVersionUID = 1L;
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java
new file mode 100644
index 0000000000000000000000000000000000000000..84a9a54769d6bd21c9ee21bf121b68b03f629850
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java
@@ -0,0 +1,102 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
+ * Copyright (c) 1997-2014,  The R Core Team
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.runtime;
+
+import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
+import com.oracle.truffle.r.runtime.context.ConsoleHandler;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+
+public class RCleanUp {
+
+    public static void cleanUp(SA_TYPE saveType, int status, boolean runLast) {
+        if (RInterfaceCallbacks.R_CleanUp.isOverridden()) {
+            RFFIFactory.getRFFI().getREmbedRFFI().cleanUp(saveType.ordinal(), status, runLast ? 1 : 0);
+        } else {
+            stdCleanUp(saveType, status, runLast);
+        }
+    }
+
+    public static void stdCleanUp(final SA_TYPE saveActionIn, int status, boolean runLast) {
+        // Output is not diverted to sink
+        ConsoleHandler consoleHandler = RContext.getInstance().getConsoleHandler();
+        SA_TYPE saveAction = saveActionIn;
+        if (saveAction == SA_TYPE.DEFAULT) {
+            saveAction = RContext.getInstance().getStartParams().getSaveAction();
+        }
+        if (saveAction == SA_TYPE.SAVEASK) {
+            if (consoleHandler.isInteractive()) {
+                W: while (true) {
+                    consoleHandler.setPrompt("");
+                    consoleHandler.print("Save workspace image? [y/n/c]: ");
+                    String response = consoleHandler.readLine();
+                    if (response == null) {
+                        saveAction = SA_TYPE.NOSAVE;
+                        break;
+                    }
+                    if (response.length() == 0) {
+                        continue;
+                    }
+                    switch (response.charAt(0)) {
+                        case 'c':
+                            consoleHandler.setPrompt("> ");
+                            throw new JumpToTopLevelException();
+                        case 'y':
+                            saveAction = SA_TYPE.SAVE;
+                            break W;
+                        case 'n':
+                            saveAction = SA_TYPE.NOSAVE;
+                            break W;
+                        default:
+                            continue;
+                    }
+                }
+            } else {
+                saveAction = RContext.getInstance().getStartParams().getSaveAction();
+            }
+        }
+
+        switch (saveAction) {
+            case SAVE:
+                if (runLast) {
+                    runDotLast();
+                }
+                /*
+                 * we do not have an efficient way to tell if the global environment is "dirty", so
+                 * we save always
+                 */
+                RContext.getEngine().checkAndRunStartupShutdownFunction("sys.save.image", new String[]{"\".RData\""});
+                RContext.getInstance().getConsoleHandler().flushHistory();
+                break;
+
+            case NOSAVE:
+                if (runLast) {
+                    runDotLast();
+                }
+                break;
+
+            case SUICIDE:
+            default:
+
+        }
+        // TODO run exit finalizers (FFI)
+        // TODO clean tmpdir
+        Utils.exit(status);
+
+    }
+
+    private static void runDotLast() {
+        RContext.getEngine().checkAndRunStartupShutdownFunction(".Last");
+        // TODO errors should return to toplevel if interactive
+        RContext.getEngine().checkAndRunStartupShutdownFunction(".Last.sys");
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCmdOptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCmdOptions.java
index 65fa24a348450aa6401eb5ca266cf08d73a88d70..9437a68768d529f3211d64ddd7b0f976ff3e7f5b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCmdOptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCmdOptions.java
@@ -73,9 +73,9 @@ public final class RCmdOptions {
         ENCODING(RCmdOptionType.STRING, false, "encoding=ENC", null, "Specify encoding to be used for stdin"),
         SAVE(RCmdOptionType.BOOLEAN, true, "save", false, "Do save workspace at the end of the session"),
         NO_SAVE(RCmdOptionType.BOOLEAN, true, "no-save", false, "Don't save it"),
-        NO_ENVIRON(RCmdOptionType.BOOLEAN, false, "no-environ", false, "Don't read the site and user environment files"),
-        NO_SITE_FILE(RCmdOptionType.BOOLEAN, false, "no-site-file", false, "Don't read the site-wide Rprofile"),
-        NO_INIT_FILE(RCmdOptionType.BOOLEAN, false, "no-init-file", false, "Don't read the user R profile"),
+        NO_ENVIRON(RCmdOptionType.BOOLEAN, true, "no-environ", false, "Don't read the site and user environment files"),
+        NO_SITE_FILE(RCmdOptionType.BOOLEAN, true, "no-site-file", false, "Don't read the site-wide Rprofile"),
+        NO_INIT_FILE(RCmdOptionType.BOOLEAN, true, "no-init-file", false, "Don't read the user R profile"),
         RESTORE(RCmdOptionType.BOOLEAN, true, "restore", true, "Do restore previously saved objects at startup"),
         NO_RESTORE_DATA(RCmdOptionType.BOOLEAN, true, "no-restore-data", false, "Don't restore previously saved objects"),
         NO_RESTORE_HISTORY(RCmdOptionType.BOOLEAN, false, "no-restore-history", false, "Don't restore the R history file"),
@@ -86,12 +86,8 @@ public final class RCmdOptions {
         QUIET(RCmdOptionType.BOOLEAN, true, "q", "quiet", false, "Don't print startup message"),
         SILENT(RCmdOptionType.BOOLEAN, true, "silent", false, "Same as --quiet"),
         SLAVE(RCmdOptionType.BOOLEAN, true, "slave", false, "Make R run as quietly as possible"),
-        INTERACTIVE(RCmdOptionType.BOOLEAN, false, "interactive", false, "Force an interactive session"),
-        VERBOSE(RCmdOptionType.BOOLEAN, false, "verbose", false, "Print more information about progress"),
-        DEBUGGER(RCmdOptionType.STRING, true, "d", "debugger=NAME", null, "Run R through debugger NAME"),
-        DEBUGGER_ARGS(RCmdOptionType.STRING, false, "debugger-args=ARGS", null, "Pass ARGS as arguments to the debugger"),
-        GUI(RCmdOptionType.STRING, false, "g TYPE", "gui=TYPE", null, "Use TYPE as GUI; possible values are 'X11' (default)\nand 'Tk'."),
-        ARCH(RCmdOptionType.STRING, false, "arch=NAME", null, "Specify a sub-architecture"),
+        INTERACTIVE(RCmdOptionType.BOOLEAN, true, "interactive", false, "Force an interactive session"),
+        VERBOSE(RCmdOptionType.BOOLEAN, true, "verbose", false, "Print more information about progress"),
         ARGS(RCmdOptionType.BOOLEAN, true, "args", false, "Skip the rest of the command line"),
         FILE(RCmdOptionType.STRING, true, "f FILE", "file=FILE", null, "Take input from 'FILE'"),
         EXPR(RCmdOptionType.REPEATED_STRING, true, "e EXPR", null, null, "Execute 'EXPR' and exit"),
@@ -278,11 +274,12 @@ public final class RCmdOptions {
      * The spec for {@code commandArgs()} states that it returns the executable by which R was
      * invoked in element 0, which is consistent with the C {@code main} function, but defines the
      * exact form to be platform independent. Java does not provide the executable (for obvious
-     * reasons) so we use "FastR".
+     * reasons) so we use "FastR". However, embedded mode does pass the executable in
+     * {@code args[0]} and we do not want to parse that!
      */
-    public static RCmdOptions parseArguments(Client client, String[] args) {
+    public static RCmdOptions parseArguments(Client client, String[] args, boolean embedded) {
         EnumMap<RCmdOption, Object> options = new EnumMap<>(RCmdOption.class);
-        int i = 0;
+        int i = embedded ? 1 : 0;
         int firstNonOptionArgIndex = args.length;
         while (i < args.length) {
             final String arg = args[i];
@@ -327,9 +324,14 @@ public final class RCmdOptions {
                 }
             }
         }
-        String[] xargs = new String[args.length + 1];
-        xargs[0] = "FastR";
-        System.arraycopy(args, 0, xargs, 1, args.length);
+        String[] xargs;
+        if (embedded) {
+            xargs = args;
+        } else {
+            xargs = new String[args.length + 1];
+            xargs[0] = "FastR";
+            System.arraycopy(args, 0, xargs, 1, args.length);
+        }
 
         // adjust for inserted executable name
         return new RCmdOptions(options, xargs, firstNonOptionArgIndex + 1);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
index 9c667604434f41fcc7775373a14bcdba6b3b295b..1c9a2d4d54a118b253be02e4587f821dfa9e5719 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
@@ -322,7 +322,6 @@ public class RDeparse {
         }
 
         private DeparseVisitor append(String str) {
-            assert !str.contains("\n");
             sb.append(str);
             return this;
         }
@@ -549,7 +548,12 @@ public class RDeparse {
                         } else if (args.length == 1) {
                             append(args[0]).append(symbol).append("NULL");
                         } else {
-                            append(args[0]).append(symbol).append(args[1]);
+                            // FIXME use call syntax until parser fixed to accept literals
+                            if (args[1] instanceof RSyntaxConstant) {
+                                append('`').append(symbol).append('`').append('(').append(args[0]).append(", ").append(args[1]).append(')');
+                            } else {
+                                append(args[0]).append(symbol).append(args[1]);
+                            }
                         }
                         return null;
                     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
index b6fe1483d2e51109a49047d6765768f07d9156b7..e8d68692064e190abdaae38f28d52c457d599a63 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
@@ -32,7 +32,6 @@ import java.util.HashMap;
 import java.util.Map;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
@@ -67,7 +66,7 @@ public final class REnvVars implements RContext.ContextState {
             // This gets expanded by R code in the system profile
         }
 
-        if (!context.getOptions().getBoolean(RCmdOption.NO_ENVIRON)) {
+        if (!context.getStartParams().getNoRenviron()) {
             String siteFile = envVars.get("R_ENVIRON");
             if (siteFile == null) {
                 siteFile = fileSystem.getPath(rHome, "etc", "Renviron.site").toString();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 9c03b86cda3f4eaebdb99d8e69b6d5db469cc628..a90d09540304fac64402f98e4bafbb04709ba768 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -192,7 +192,7 @@ public final class RError extends RuntimeException {
 
     /**
      * A temporary error that indicates an unimplemented feature where terminating the VM using
-     * {@link Utils#fatalError(String)} would be inappropriate.
+     * {@link Utils#rSuicide(String)} would be inappropriate.
      */
     @TruffleBoundary
     public static RError nyi(RBaseNode node, String msg) {
@@ -675,6 +675,9 @@ public final class RError extends RuntimeException {
         BROWSER_QUIT("cannot quit from browser"),
         QUIT_ASK("one of \"yes\", \"no\", \"ask\" or \"default\" expected."),
         QUIT_SAVE("unrecognized value of 'save'"),
+        QUIT_ASK_INTERACTIVE("save=\"ask\" in non-interactive use: command-line default will be used"),
+        QUIT_INVALID_STATUS("invalid 'status', 0 assumed"),
+        QUIT_INVALID_RUNLAST("invalid 'runLast', FALSE assumed"),
         ENVIRONMENTS_COERCE("environments cannot be coerced to other types"),
         CLOSURE_COERCE("cannot coerce type 'closure' to vector of type 'integer'"),
         ROWSUM_NAMES_NOT_CHAR("row names are not character"),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
index 508a44b4e52978d05d46a854080aa70fd7b58392..911a09d8291a12e6d029ee2120a74c3b58f83c0a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
@@ -163,12 +163,28 @@ public class RErrorHandling {
         }
     }
 
+    public static final class HandlerStacks {
+        public final Object handlerStack;
+        public final Object restartStack;
+
+        private HandlerStacks(Object handlerStack, Object restartStack) {
+            this.handlerStack = handlerStack;
+            this.restartStack = restartStack;
+        }
+    }
+
     private static final Object RESTART_TOKEN = new Object();
 
     private static ContextStateImpl getRErrorHandlingState() {
         return RContext.getInstance().stateRErrorHandling;
     }
 
+    public static HandlerStacks resetAndGetHandlerStacks() {
+        HandlerStacks result = new HandlerStacks(getRErrorHandlingState().handlerStack, getRErrorHandlingState().restartStack);
+        resetStacks();
+        return result;
+    }
+
     public static Object getHandlerStack() {
         return getRErrorHandlingState().handlerStack;
     }
@@ -177,6 +193,21 @@ public class RErrorHandling {
         return getRErrorHandlingState().restartStack;
     }
 
+    /**
+     * Resets the handler stacks for a "top-level" evaluation ({@code Rf_tryEval} in the R FFI. This
+     * must be preceded by calls to {@link #getHandlerStack} and {@link #getRestartStack()} and
+     * followed by {@link #restoreStacks} after the evaluation completes.
+     */
+    public static void resetStacks() {
+        ContextStateImpl errorHandlingState = getRErrorHandlingState();
+        errorHandlingState.handlerStack = RNull.instance;
+        errorHandlingState.restartStack = RNull.instance;
+    }
+
+    public static void restoreHandlerStacks(HandlerStacks handlerStacks) {
+        restoreStacks(handlerStacks.handlerStack, handlerStacks.restartStack);
+    }
+
     public static void restoreStacks(Object savedHandlerStack, Object savedRestartStack) {
         ContextStateImpl errorHandlingState = getRErrorHandlingState();
         errorHandlingState.handlerStack = savedHandlerStack;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInterfaceCallbacks.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInterfaceCallbacks.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b95eeb7dc6075365e7acf11eb3bfa002edfaef3
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInterfaceCallbacks.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime;
+
+/**
+ * Support for callbacks in embedded mode for certain VM operations.
+ *
+ */
+public enum RInterfaceCallbacks {
+    R_Suicide,
+    R_ShowMessage,
+    R_ReadConsole,
+    R_WriteConsole,
+    // R_WriteConsoleEx, handled in native code
+    R_ResetConsole,
+    R_FlushConsole,
+    R_ClearerrConsole,
+    R_Busy,
+    R_CleanUp;
+
+    private boolean overridden;
+
+    public boolean isOverridden() {
+        return overridden;
+    }
+
+    /**
+     * Upcalled from native code.
+     */
+    @SuppressWarnings("unused")
+    private static void override(String name) {
+        RInterfaceCallbacks.valueOf(name).overridden = true;
+    }
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java
index 8208e1a3c4f43fc69596d5e91f8dfa118422e5ee..17fcab5f0bede00e64fd466d767abf374976494a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java
@@ -29,13 +29,14 @@ import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.FileSystems;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.util.Date;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.runtime.context.RContext;
 
 /**
  * This class is intended to be used for internal errors that do not correspond to R errors.
@@ -149,7 +150,8 @@ public final class RInternalError extends Error {
                 System.err.println(verboseStackTrace);
             }
             if (FastROptions.PrintErrorStacktracesToFile.getBooleanValue()) {
-                try (BufferedWriter writer = Files.newBufferedWriter(FileSystems.getDefault().getPath(REnvVars.rHome(), "fastr_errors.log"), StandardCharsets.UTF_8, StandardOpenOption.APPEND,
+                Path logfile = Utils.getLogPath("fastr_errors.log");
+                try (BufferedWriter writer = Files.newBufferedWriter(logfile, StandardCharsets.UTF_8, StandardOpenOption.APPEND,
                                 StandardOpenOption.CREATE)) {
                     writer.append(new Date().toString()).append('\n');
                     writer.append(out.toString()).append('\n');
@@ -157,6 +159,9 @@ public final class RInternalError extends Error {
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
+                if (RContext.isEmbedded()) {
+                    Utils.rSuicide("FastR internal error");
+                }
             }
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
index e6b567cdbbd92609f59bd587aba25f64d2e64e5b..012d2a4f2af7b6b943c90c753acf7df1eea8d362 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
@@ -18,7 +18,6 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
-import com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -29,7 +28,9 @@ import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 
 /**
  * Central location for all R options, that is for the {@code options(...)} and {@code getOption}
@@ -52,6 +53,7 @@ public class ROptions {
 
         private ContextStateImpl(HashMap<String, Object> map) {
             this.map = map;
+            // cannot call updateDotOptions here
         }
 
         public Set<Entry<String, Object>> getValues() {
@@ -84,18 +86,38 @@ public class ROptions {
             } else {
                 map.put(name, coercedValue);
             }
+            updateDotOptions();
             return previous;
         }
 
         public static ContextStateImpl newContext(RContext context, REnvVars envVars) {
             HashMap<String, Object> map = new HashMap<>();
             if (context.getKind() == ContextKind.SHARE_NOTHING) {
-                applyDefaults(map, context.getOptions(), envVars);
+                applyDefaults(map, context.getStartParams(), envVars);
             } else {
                 map.putAll(context.getParent().stateROptions.map);
             }
             return new ContextStateImpl(map);
         }
+
+        /**
+         * Creates/updates the {@code .Options} variable in {@code baseenv}.
+         */
+        public void updateDotOptions() {
+            // TODO make incremental?
+            RPairList ppl = null;
+            RPairList head = null;
+            for (Map.Entry<String, Object> entry : getValues()) {
+                RPairList pl = RDataFactory.createPairList(entry.getValue(), RNull.instance, RDataFactory.createSymbol(entry.getKey()));
+                if (ppl != null) {
+                    ppl.setCdr(pl);
+                } else {
+                    head = pl;
+                }
+                ppl = pl;
+            }
+            REnvironment.baseEnv().safePut(DOT_OPTIONS, head);
+        }
     }
 
     @SuppressWarnings("serial")
@@ -109,18 +131,23 @@ public class ROptions {
         }
     }
 
+    /**
+     * S compatibility - pair list of the options.
+     */
+    private static final String DOT_OPTIONS = ".Options";
+
     private static final Set<String> CHECKED_OPTIONS_SET = new HashSet<>(Arrays.asList("width", "deparse.cutoff", "digits", "expressions", "keep.source", "editor", "continue", "prompt", "contrasts",
                     "check.bounds", "warn", "warning.length", "warning.expression", "max.print", "nwarnings", "error", "show.error.messages", "echo", "OutDec", "max.contour.segments",
                     "rl_word_breaks", "warnPartialMatchDollar", "warnPartialMatchArgs", "warnPartialMatchAttr", "showWarnCalls", "showErrorCalls", "showNCalls", "par.ask.default",
                     "browserNLdisabled", "CBoundsCheck"));
 
-    private static void applyDefaults(HashMap<String, Object> map, RCmdOptions options, REnvVars envVars) {
+    private static void applyDefaults(HashMap<String, Object> map, RStartParams startParams, REnvVars envVars) {
         map.put("add.smooth", RDataFactory.createSharedLogicalVectorFromScalar(true));
         map.put("check.bounds", RDataFactory.createSharedLogicalVectorFromScalar(false));
         map.put("continue", RDataFactory.createSharedStringVectorFromScalar("+ "));
         map.put("deparse.cutoff", RDataFactory.createSharedIntVectorFromScalar(60));
         map.put("digits", RDataFactory.createSharedIntVectorFromScalar(7));
-        map.put("echo", RDataFactory.createSharedLogicalVectorFromScalar(options.getBoolean(RCmdOption.SLAVE) ? false : true));
+        map.put("echo", RDataFactory.createSharedLogicalVectorFromScalar(startParams.getSlave() ? false : true));
         map.put("encoding", RDataFactory.createSharedStringVectorFromScalar("native.enc"));
         map.put("expressions", RDataFactory.createSharedIntVectorFromScalar(5000));
         boolean keepPkgSource = optionFromEnvVar("R_KEEP_PKG_SOURCE", envVars);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
index 262505493a4d0916f9665b8dac02b02d0c79b826..17418510bfaf43251b9bd944c8f300ad2a78c679 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
@@ -22,9 +22,6 @@
  */
 package com.oracle.truffle.r.runtime;
 
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_INIT_FILE;
-import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_SITE_FILE;
-
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.FileSystem;
@@ -47,7 +44,7 @@ public final class RProfile implements RContext.ContextState {
         Source newSiteProfile = null;
         Source newUserProfile = null;
 
-        if (!context.getOptions().getBoolean(NO_SITE_FILE)) {
+        if (context.getStartParams().getLoadSiteFile()) {
             String siteProfilePath = envVars.get("R_PROFILE");
             if (siteProfilePath == null) {
                 siteProfilePath = fileSystem.getPath(rHome, "etc", "Rprofile.site").toString();
@@ -60,7 +57,7 @@ public final class RProfile implements RContext.ContextState {
             }
         }
 
-        if (!context.getOptions().getBoolean(NO_INIT_FILE)) {
+        if (context.getStartParams().getLoadInitFile()) {
             String userProfilePath = envVars.get("R_PROFILE_USER");
             if (userProfilePath == null) {
                 String dotRenviron = ".Rprofile";
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
index 0b0c7bdd7e31cd1e176f7b713f397308f78eebd1..a6f96c9b38872c451e009a865fcec257c5b62413 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
@@ -170,11 +170,6 @@ public interface RRuntimeASTAccess {
      */
     void traceAllFunctions();
 
-    /**
-     * Project circularity workaround.
-     */
-    void enableDebug(RFunction func);
-
     /**
      * Project circularity workaround. Equivalent to
      * RASTUtils.unwrap(promise.getRep()).asRSyntaxNode().
@@ -190,4 +185,10 @@ public interface RRuntimeASTAccess {
 
     RBaseNode createConstantNode(Object o);
 
+    boolean enableDebug(RFunction func, boolean once);
+
+    boolean disableDebug(RFunction func);
+
+    boolean isDebugged(RFunction func);
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index b930856972ac8930e17853a30b645baf8858c1ad..3c826891dd099b8bcfe4952440c971abc1bb4f13 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -568,7 +568,7 @@ public class RSerialize {
                                 MaterializedFrame enclosingFrame = ((REnvironment) rpl.getTag()).getFrame();
                                 RFunction func = parseFunction(constants, deparse, enclosingFrame, currentFunctionName);
 
-                                copyAttributes(func, rpl.getAttributes());
+                                RAttributes.copyAttributes(func, rpl.getAttributes());
                                 result = func;
                             } catch (Throwable ex) {
                                 throw new RInternalError(ex, "unserialize - failed to eval deparsed closure");
@@ -593,7 +593,7 @@ public class RSerialize {
                                 result = expr.getDataAt(0);
                                 RAttributes attrs = pl.getAttributes();
                                 if (result instanceof RAttributable) {
-                                    copyAttributes((RAttributable) result, attrs);
+                                    RAttributes.copyAttributes((RAttributable) result, attrs);
                                 }
                             }
                             break;
@@ -846,17 +846,6 @@ public class RSerialize {
             return result;
         }
 
-        private static void copyAttributes(RAttributable obj, RAttributes attrs) {
-            if (attrs == null) {
-                return;
-            }
-            Iterator<RAttribute> iter = attrs.iterator();
-            while (iter.hasNext()) {
-                RAttribute attr = iter.next();
-                obj.setAttr(attr.getName(), attr.getValue());
-            }
-        }
-
         private RExpression parse(Map<String, Object> constants, String deparseRaw) throws IOException {
             try {
                 Source source = RSource.fromPackageTextInternal(deparseRaw, packageName);
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 7b3291b64fe45091dd12cc771c50e722939754aa..29ebcd0c94c992a08fc2e6a3b616eb2e6b9c140a 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
@@ -72,7 +72,9 @@ public class RSource {
         TCK_INIT("<tck_initialization>"),
         PACKAGE("<package:%s deparse>"),
         DEPARSE_ERROR("<package_deparse_error>"),
-        LAPPLY("<lapply>");
+        LAPPLY("<lapply>"),
+        R_PARSEVECTOR("<R_ParseVector>"),
+        PAIRLIST_DEPARSE("<pairlist deparse>");
 
         public final String string;
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RStartParams.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RStartParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..282508c41e25388db9d033b7eaea8dca6dd15c82
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RStartParams.java
@@ -0,0 +1,260 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995-2015, The R Core Team
+ * Copyright (c) 2003, The R Foundation
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.runtime;
+
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.RESTORE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_READLINE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_RESTORE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_RESTORE_DATA;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_ENVIRON;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_SITE_FILE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_INIT_FILE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.QUIET;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.SILENT;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.SAVE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.NO_SAVE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.SLAVE;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.VANILLA;
+import static com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption.VERBOSE;
+
+import com.oracle.truffle.r.runtime.context.RContext;
+
+/**
+ * Defines startup parameters (that can be customized by embedding apps).
+ */
+public class RStartParams {
+
+    public enum SA_TYPE {
+        NORESTORE(null),
+        RESTORE(null),
+        DEFAULT("default"),
+        NOSAVE("no"),
+        SAVE("yes"),
+        SAVEASK("ask"),
+        SUICIDE(null);
+
+        private String userName;
+
+        SA_TYPE(String userName) {
+            this.userName = userName;
+        }
+
+        public static final String[] SAVE_VALUES = new String[]{"yes", "no", "ask", "default"};
+
+        public String getUserName() {
+            return userName;
+        }
+
+        public static SA_TYPE fromString(String s) {
+            for (SA_TYPE t : values()) {
+                if (t.userName != null && t.userName.equals(s)) {
+                    return t;
+                }
+            }
+            return null;
+        }
+    }
+
+    private boolean quiet;
+    private boolean slave;
+    /**
+     * The setting of this value in GNU R is unusual and not simply based on the value of the
+     * --interactive option, so we do not check the option in
+     * {@link #RStartParams(RCmdOptions, boolean)}, but later in {@code RCommand}.
+     */
+    private boolean interactive = true;
+    private boolean verbose;
+    private boolean loadSiteFile = true;
+    private boolean loadInitFile = true;
+    private boolean debugInitFile;
+    private SA_TYPE restoreAction = SA_TYPE.RESTORE;
+    private SA_TYPE saveAction = SA_TYPE.SAVEASK;
+    private boolean noRenviron;
+    /**
+     * This is not a configurable option, but it is set on the command line and needs to be stored
+     * somewhere.
+     */
+    private boolean noReadline;
+
+    /**
+     * The original command line arguments that were parsed by {@link RCmdOptions}.
+     */
+    private String[] arguments;
+
+    /**
+     * Indicates that FastR is running embedded.
+     */
+    private boolean embedded;
+
+    public RStartParams(RCmdOptions options, boolean embedded) {
+        this.arguments = options.getArguments();
+        this.embedded = embedded;
+        if (options.getBoolean(VERBOSE)) {
+            this.verbose = true;
+        }
+        if (options.getBoolean(QUIET) || options.getBoolean(SILENT)) {
+            this.quiet = true;
+        }
+        if (options.getBoolean(NO_SITE_FILE)) {
+            this.loadSiteFile = false;
+        }
+        if (options.getBoolean(NO_INIT_FILE)) {
+            this.loadInitFile = false;
+        }
+        if (options.getBoolean(NO_ENVIRON)) {
+            this.noRenviron = true;
+        }
+        if (options.getBoolean(SAVE)) {
+            this.saveAction = SA_TYPE.SAVE;
+        }
+        if (options.getBoolean(NO_SAVE)) {
+            this.saveAction = SA_TYPE.NOSAVE;
+        }
+        if (options.getBoolean(RESTORE)) {
+            this.restoreAction = SA_TYPE.RESTORE;
+        }
+        if (options.getBoolean(NO_RESTORE) || options.getBoolean(NO_RESTORE_DATA)) {
+            this.restoreAction = SA_TYPE.NORESTORE;
+        }
+        if (options.getBoolean(NO_READLINE)) {
+            this.noReadline = true;
+        }
+        if (options.getBoolean(SLAVE)) {
+            this.slave = true;
+            this.quiet = true;
+            this.setSaveAction(SA_TYPE.NOSAVE);
+        }
+
+        if (options.getBoolean(VANILLA)) {
+            this.setSaveAction(SA_TYPE.NOSAVE);
+            this.noRenviron = true;
+            this.loadInitFile = false;
+            this.restoreAction = SA_TYPE.NORESTORE;
+        }
+    }
+
+    /**
+     * Only upcalled from native code.
+     */
+    @SuppressWarnings("unused")
+    private static void setParams(boolean quietA, boolean slaveA, boolean interactiveA, boolean verboseA, boolean loadSiteFileA,
+                    boolean loadInitFileA, boolean debugInitFileA, int restoreActionA,
+                    int saveActionA, boolean noRenvironA) {
+        RStartParams params = RContext.getInstance().getStartParams();
+        params.setQuiet(quietA);
+        params.setSlave(slaveA);
+        params.setInteractive(interactiveA);
+        params.setVerbose(verboseA);
+        params.setLoadSiteFile(loadSiteFileA);
+        params.setLoadInitFile(loadInitFileA);
+        params.setDebugInitFile(debugInitFileA);
+        params.setSaveAction(SA_TYPE.values()[saveActionA]);
+        params.setRestoreAction(SA_TYPE.values()[restoreActionA]);
+        params.setNoRenviron(noRenvironA);
+    }
+
+    public boolean getQuiet() {
+        return this.quiet;
+    }
+
+    public void setQuiet(boolean b) {
+        this.quiet = b;
+    }
+
+    public boolean getSlave() {
+        return slave;
+    }
+
+    public void setSlave(boolean b) {
+        this.slave = b;
+    }
+
+    public boolean getInteractive() {
+        return this.interactive;
+    }
+
+    public void setInteractive(boolean b) {
+        this.interactive = b;
+    }
+
+    public boolean getVerbose() {
+        return this.verbose;
+    }
+
+    public void setVerbose(boolean b) {
+        this.verbose = b;
+    }
+
+    public boolean getLoadSiteFile() {
+        return this.loadSiteFile;
+    }
+
+    public void setLoadSiteFile(boolean b) {
+        this.loadSiteFile = b;
+    }
+
+    public boolean getLoadInitFile() {
+        return this.loadInitFile;
+    }
+
+    public void setLoadInitFile(boolean b) {
+        this.loadInitFile = b;
+    }
+
+    public boolean getDebugInitFile() {
+        return this.debugInitFile;
+    }
+
+    public void setDebugInitFile(boolean b) {
+        this.debugInitFile = b;
+    }
+
+    public SA_TYPE getRestoreAction() {
+        return this.restoreAction;
+    }
+
+    public void setRestoreAction(SA_TYPE a) {
+        this.restoreAction = a;
+    }
+
+    public SA_TYPE getSaveAction() {
+        return this.saveAction;
+    }
+
+    public void setSaveAction(SA_TYPE a) {
+        this.saveAction = a;
+    }
+
+    public boolean getNoRenviron() {
+        return this.noRenviron;
+    }
+
+    public void setNoRenviron(boolean b) {
+        this.noRenviron = b;
+    }
+
+    public boolean getNoReadline() {
+        return this.noReadline;
+    }
+
+    public String[] getArguments() {
+        return arguments;
+    }
+
+    public void setEmbedded() {
+        this.embedded = true;
+    }
+
+    public boolean getEmbedded() {
+        return embedded;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
index b579ea12dd32c1d3848008d6d0ef04e9a15c3287..74f8ed2ea849735170effb4a05c9e8e50f3d0466 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
@@ -50,7 +50,6 @@ import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.nodes.GraphPrintVisitor;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption;
 import com.oracle.truffle.r.runtime.conn.StdConnections;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -61,6 +60,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 public final class Utils {
@@ -156,21 +156,17 @@ public final class Utils {
          * polyglot context are.
          */
         RPerfStats.report();
-        if (RContext.getInstance() != null && RContext.getInstance().getOptions() != null && RContext.getInstance().getOptions().getString(RCmdOption.DEBUGGER) != null) {
-            throw new DebugExitException();
-        } else {
-            try {
-                /*
-                 * This is not the proper way to dispose a PolyglotEngine, but it doesn't matter
-                 * since we're going to System.exit anyway.
-                 */
-                RContext.getInstance().destroy();
-            } catch (Throwable t) {
-                // ignore
-            }
-            System.exit(status);
-            return null;
+        try {
+            /*
+             * This is not the proper way to dispose a PolyglotEngine, but it doesn't matter since
+             * we're going to System.exit anyway.
+             */
+            RContext.getInstance().destroy();
+        } catch (Throwable t) {
+            // ignore
         }
+        System.exit(status);
+        return null;
     }
 
     public static RuntimeException fail(String msg) {
@@ -180,8 +176,12 @@ public final class Utils {
         throw Utils.exit(2);
     }
 
-    public static RuntimeException fatalError(String msg) {
-        System.err.println("Fatal error: " + msg);
+    public static RuntimeException rSuicide(String msg) {
+        if (RInterfaceCallbacks.R_Suicide.isOverridden()) {
+            RFFIFactory.getRFFI().getREmbedRFFI().suicide(msg);
+        } else {
+            System.err.println("Fatal error: " + msg);
+        }
         throw Utils.exit(2);
     }
 
@@ -249,6 +249,19 @@ public final class Utils {
         wdState().setCurrent(path);
     }
 
+    /**
+     * Returns a {@link Path} for a log file with base name {@code fileName}, taking into account
+     * whether the system is running in embedded mode. In the latter case, we can't assume that the
+     * cwd is writable. Plus some embedded apps, e.g. RStudio, spawn multiple R sub-processes
+     * concurrently so we tag the file with the pid.
+     */
+    public static Path getLogPath(String fileName) {
+        String root = RContext.isEmbedded() ? "/tmp" : REnvVars.rHome();
+        int pid = RFFIFactory.getRFFI().getBaseRFFI().getpid();
+        String baseName = RContext.isEmbedded() ? fileName + "-" + Integer.toString(pid) : fileName;
+        return FileSystems.getDefault().getPath(root, baseName);
+    }
+
     /**
      * Performs "~" expansion and also checks whether we need to take special case over relative
      * paths due to the curwd having moved from the initial setting. In the latter case, if the path
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java
index ab347547db7f780f485681e80130085479e6ca0c..f238108b70c6963f407b0fb1bcaaf09e6df6f49f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java
@@ -95,12 +95,6 @@ public interface ConsoleHandler {
     @TruffleBoundary
     void setPrompt(String prompt);
 
-    /**
-     * Get the console width.
-     */
-    @TruffleBoundary
-    int getWidth();
-
     String getInputDescription();
 
     default void setHistoryFrom(@SuppressWarnings("unused") File file) {
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/ContextInfo.java
index 4980ef69ae8ba14be31c4ce41bfe8d2b857e90c1..a780f005b4f26e7522d84d2c66650d9b488277fc 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/ContextInfo.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.context;
 
+import java.io.IOException;
 import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -29,7 +30,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.vm.PolyglotEngine;
-import com.oracle.truffle.r.runtime.RCmdOptions;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 
 /**
@@ -39,12 +41,12 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
  * instance (it will be stored in the "fastrContextInfo" global symbol).
  */
 public final class ContextInfo implements TruffleObject {
-    static final String GLOBAL_SYMBOL = "fastrContextInfo";
+    public static final String GLOBAL_SYMBOL = "fastrContextInfo";
 
     private static final ConcurrentHashMap<Integer, ContextInfo> contextInfos = new ConcurrentHashMap<>();
     private static final AtomicInteger contextInfoIds = new AtomicInteger();
 
-    private final RCmdOptions options;
+    private final RStartParams startParams;
     private final RContext.ContextKind kind;
     private final TimeZone systemTimeZone;
 
@@ -57,8 +59,8 @@ public final class ContextInfo implements TruffleObject {
     private final int id;
     private PolyglotEngine vm;
 
-    private ContextInfo(RCmdOptions options, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone, int id) {
-        this.options = options;
+    private ContextInfo(RStartParams startParams, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone, int id) {
+        this.startParams = startParams;
         this.kind = kind;
         this.parent = parent;
         this.consoleHandler = consoleHandler;
@@ -78,21 +80,21 @@ public final class ContextInfo implements TruffleObject {
      * @param parent if non-null {@code null}, the parent creating the context
      * @param kind defines the degree to which this context shares base and package environments
      *            with its parent
-     * @param options the command line arguments passed this R session
+     * @param startParams the start parameters passed this R session
      * @param consoleHandler a {@link ConsoleHandler} for output
      * @param systemTimeZone the system's time zone
      */
-    public static ContextInfo create(RCmdOptions options, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone) {
+    public static ContextInfo create(RStartParams startParams, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone) {
         int id = contextInfoIds.incrementAndGet();
-        return new ContextInfo(options, kind, parent, consoleHandler, systemTimeZone, id);
+        return new ContextInfo(startParams, kind, parent, consoleHandler, systemTimeZone, id);
     }
 
-    public static ContextInfo create(RCmdOptions options, ContextKind kind, RContext parent, ConsoleHandler consoleHandler) {
-        return create(options, kind, parent, consoleHandler, TimeZone.getDefault());
+    public static ContextInfo create(RStartParams startParams, ContextKind kind, RContext parent, ConsoleHandler consoleHandler) {
+        return create(startParams, kind, parent, consoleHandler, TimeZone.getDefault());
     }
 
-    public static int createDeferred(RCmdOptions options, ContextKind kind, RContext parent, ConsoleHandler consoleHandler) {
-        ContextInfo info = create(options, kind, parent, consoleHandler, TimeZone.getDefault());
+    public static int createDeferred(RStartParams startParams, ContextKind kind, RContext parent, ConsoleHandler consoleHandler) {
+        ContextInfo info = create(startParams, kind, parent, consoleHandler, TimeZone.getDefault());
         contextInfos.put(info.id, info);
         return info.id;
     }
@@ -101,8 +103,16 @@ public final class ContextInfo implements TruffleObject {
         return contextInfos.get(id);
     }
 
-    public RCmdOptions getOptions() {
-        return options;
+    public static ContextInfo getContextInfo(PolyglotEngine vm) {
+        try {
+            return (ContextInfo) vm.findGlobalSymbol(ContextInfo.GLOBAL_SYMBOL).get();
+        } catch (IOException ex) {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    public RStartParams getStartParams() {
+        return startParams;
     }
 
     public ContextKind getKind() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java
index e7cd144b26891a3aaa4c7872024a40c8afd99f5e..18f2a36cceb1ed6df87252416c914869ebb2d624 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java
@@ -87,11 +87,6 @@ public class DefaultConsoleHandler implements ConsoleHandler {
         this.prompt = prompt;
     }
 
-    @Override
-    public int getWidth() {
-        return 80;
-    }
-
     @Override
     public String getInputDescription() {
         return "<PolyglotEngine env input>";
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 25accd14e61b46ebeb55b1a213a1a119daed0143..ec21c2f7e22ddbd63241af45c167c0eb31bfcef4 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
@@ -58,6 +58,7 @@ import com.oracle.truffle.r.runtime.RProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RRuntimeASTAccess;
 import com.oracle.truffle.r.runtime.RSerialize;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RVisibility;
 import com.oracle.truffle.r.runtime.Utils;
@@ -71,6 +72,7 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.RFFIContextStateFactory;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
@@ -291,6 +293,11 @@ public final class RContext extends ExecutionContext implements TruffleObject {
 
     private boolean nullS4Object = false;
 
+    /**
+     * This used to prevent a "quit" from the browser (as per GnuR).
+     */
+    private boolean inBrowser = false;
+
     private boolean active;
 
     private PrimitiveMethodsInfo primitiveMethodsInfo;
@@ -301,6 +308,12 @@ public final class RContext extends ExecutionContext implements TruffleObject {
      */
     @CompilationFinal private static boolean ignoreVisibility;
 
+    /**
+     * Set to {@code true} when in embedded mode to allow other parts of the system to determine
+     * whether embedded mode is in effect, <b>before</b> the initial context is created.
+     */
+    private static boolean embedded;
+
     /*
      * Workarounds to finesse project circularities between runtime/nodes.
      */
@@ -352,9 +365,9 @@ public final class RContext extends ExecutionContext implements TruffleObject {
      * could do this more dynamically with a registration process, perhaps driven by an annotation
      * processor, but the set is relatively small, so we just enumerate them here.
      */
-    public final REnvVars stateREnvVars;
-    public final RProfile stateRProfile;
-    public final ROptions.ContextStateImpl stateROptions;
+    public REnvVars stateREnvVars;
+    public RProfile stateRProfile;
+    public ROptions.ContextStateImpl stateROptions;
     public final REnvironment.ContextStateImpl stateREnvironment;
     public final RErrorHandling.ContextStateImpl stateRErrorHandling;
     public final ConnectionSupport.ContextStateImpl stateRConnection;
@@ -371,10 +384,23 @@ public final class RContext extends ExecutionContext implements TruffleObject {
                         stateLazyDBCache, stateInstrumentation};
     }
 
+    public static void setEmbedded() {
+        embedded = true;
+    }
+
+    public static boolean isEmbedded() {
+        return embedded;
+    }
+
     private RContext(Env env, Instrumenter instrumenter, boolean isInitial) {
         ContextInfo initialInfo = (ContextInfo) env.importSymbol(ContextInfo.GLOBAL_SYMBOL);
         if (initialInfo == null) {
-            this.info = ContextInfo.create(RCmdOptions.parseArguments(Client.R, new String[0]), ContextKind.SHARE_NOTHING, null, new DefaultConsoleHandler(env.in(), env.out()));
+            /*
+             * This implies that FastR is being invoked initially from another Truffle language and
+             * not via RCommand/RscriptCommand.
+             */
+            this.info = ContextInfo.create(new RStartParams(RCmdOptions.parseArguments(Client.R, new String[0], false), false), ContextKind.SHARE_NOTHING, null,
+                            new DefaultConsoleHandler(env.in(), env.out()));
         } else {
             this.info = initialInfo;
         }
@@ -421,9 +447,9 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         assert !active;
         active = true;
         attachThread();
-        stateREnvVars = REnvVars.newContext(this);
-        stateRProfile = RProfile.newContext(this, stateREnvVars);
-        stateROptions = ROptions.ContextStateImpl.newContext(this, stateREnvVars);
+        if (!embedded) {
+            doEnvOptionsProfileInitialization();
+        }
         stateREnvironment = REnvironment.ContextStateImpl.newContext(this);
         stateRErrorHandling = RErrorHandling.ContextStateImpl.newContext(this);
         stateRConnection = ConnectionSupport.ContextStateImpl.newContext(this);
@@ -434,7 +460,11 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         stateLazyDBCache = LazyDBCache.ContextStateImpl.newContext(this);
         stateInstrumentation = InstrumentationState.newContext(this, instrumenter);
         stateInternalCode = ContextStateImpl.newContext(this);
-        engine.activate(stateREnvironment);
+
+        if (!embedded) {
+            validateContextStates();
+            engine.activate(stateREnvironment);
+        }
 
         if (info.getKind() == ContextKind.SHARE_PARENT_RW) {
             if (info.getParent().sharedChild != null) {
@@ -445,12 +475,34 @@ public final class RContext extends ExecutionContext implements TruffleObject {
             // that methods package is loaded
             this.methodTableDispatchOn = info.getParent().methodTableDispatchOn;
         }
+        if (isInitial && !embedded) {
+            RFFIFactory.getRFFI().getCallRFFI().setInteractive(isInteractive());
+            initialContextInitialized = true;
+        }
+    }
+
+    /**
+     * Factored out for embedded setup, where this initialization may be customized after the
+     * context is created but before VM really starts execution.
+     */
+    private void doEnvOptionsProfileInitialization() {
+        stateREnvVars = REnvVars.newContext(this);
+        stateROptions = ROptions.ContextStateImpl.newContext(this, stateREnvVars);
+        stateRProfile = RProfile.newContext(this, stateREnvVars);
+    }
+
+    public void completeEmbeddedInitialization() {
+        doEnvOptionsProfileInitialization();
+        validateContextStates();
+        engine.activate(stateREnvironment);
+        stateROptions.updateDotOptions();
+        initialContextInitialized = true;
+    }
+
+    private void validateContextStates() {
         for (ContextState state : contextStates()) {
             assert state != null;
         }
-        if (isInitial) {
-            initialContextInitialized = true;
-        }
     }
 
     /**
@@ -538,7 +590,12 @@ public final class RContext extends ExecutionContext implements TruffleObject {
 
     public void setVisible(boolean v) {
         if (!FastROptions.IgnoreVisibility.getBooleanValue()) {
-            resultVisible = v;
+            /*
+             * Prevent printing the dummy expression used to force creation of initial context
+             */
+            if (initialContextInitialized || !embedded) {
+                resultVisible = v;
+            }
         }
     }
 
@@ -566,6 +623,14 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         nullS4Object = on;
     }
 
+    public boolean isInBrowser() {
+        return inBrowser;
+    }
+
+    public void setInBrowser(boolean on) {
+        inBrowser = on;
+    }
+
     public boolean allowPrimitiveMethods() {
         return allowPrimitiveMethods;
     }
@@ -643,8 +708,8 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         return foreignAccessFactory;
     }
 
-    public RCmdOptions getOptions() {
-        return info.getOptions();
+    public RStartParams getStartParams() {
+        return info.getStartParams();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributes.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributes.java
index 781900ed66e319c66d8d3e761c1875c886caff2b..69956311d4b3aa3156ec465a70e3fa9fceb015b0 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributes.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributes.java
@@ -81,6 +81,17 @@ public final class RAttributes implements Iterable<RAttributes.RAttribute> {
         return new RAttributes(names, values);
     }
 
+    public static void copyAttributes(RAttributable obj, RAttributes attrs) {
+        if (attrs == null) {
+            return;
+        }
+        Iterator<RAttribute> iter = attrs.iterator();
+        while (iter.hasNext()) {
+            RAttribute attr = iter.next();
+            obj.setAttr(attr.getName(), attr.getValue());
+        }
+    }
+
     /**
      * The implementation class which is separate to avoid a circularity that would result from the
      * {@code Iterable} in the abstract class.
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index a50f0f393f346949f4cfa5da26c9dfbf0b8a5d96..547e402be30f5f69749d0fc093efb87aaa6b877a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -436,6 +436,10 @@ public final class RDataFactory {
         return traceDataCreated(new RPromise.PromisedPromise(exprClosure, eagerValue, notChangedNonLocally, targetFrame, feedback));
     }
 
+    public static Object createLangPairList(int size) {
+        return size == 0 ? RNull.instance : traceDataCreated(RPairList.create(size, SEXPTYPE.LANGSXP));
+    }
+
     public static Object createPairList(int size) {
         return size == 0 ? RNull.instance : traceDataCreated(RPairList.create(size));
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
index a0f8a0ac3928dab45c8ebcfd282ac2b1877dc512..7a1944f3ea0fffa3b0f70da0dc5bc55795507a71 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
@@ -75,8 +75,12 @@ public class RPairList extends RSharingAttributeStorage implements RAbstractCont
     /**
      * Creates a new pair list of given size > 0. Note: pair list of size 0 is NULL.
      */
+    public static RPairList create(int size) {
+        return create(size, null);
+    }
+
     @TruffleBoundary
-    public static Object create(int size) {
+    public static RPairList create(int size, SEXPTYPE type) {
         assert size > 0 : "a pair list of size = 0 does not exist, it should be NULL";
         RPairList result = new RPairList();
         for (int i = 1; i < size; i++) {
@@ -84,6 +88,9 @@ public class RPairList extends RSharingAttributeStorage implements RAbstractCont
             result = new RPairList();
             result.cdr = tmp;
         }
+        if (type != null) {
+            result.type = type;
+        }
         return result;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
index ed1192edcfe7ab6e26cdc5b3b6380c0e6d0dab21..d54831170d0c97c111fdda780c0abe264dd2b5b9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
@@ -1050,6 +1050,11 @@ public abstract class REnvironment extends RAttributeStorage {
             super(EMPTY_ENV_NAME, new REnvEmptyFrameAccess());
         }
 
+        @Override
+        public REnvironment getParent() {
+            return null;
+        }
+
         @Override
         public void put(String key, Object value) throws PutException {
             throw new PutException(RError.Message.ENV_ASSIGN_EMPTY);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
index 57aaccd52db9cf7d102cb569d1d1b67215f2436b..8770a46110928aa432433cce70c077fa435e68df 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -47,4 +47,9 @@ public interface CallRFFI {
      * call sets the value.
      */
     void setTempDir(String tempDir);
+
+    /**
+     * Sets the {@code R_Interactive} FFI variable. Similar rationale to {#link setTmpDir}.
+     */
+    void setInteractive(boolean interactive);
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
index 9b43c21555075e964299de193de37c928bd17d70..28b50af8c8b3d5842794fb01c39740f181fac876 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
@@ -15,14 +15,12 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.Deque;
 import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.Semaphore;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.RErrorException;
-import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.Utils;
@@ -112,7 +110,7 @@ public class DLL {
 
     }
 
-    public static class DLLInfo {
+    public static final class DLLInfo {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"name", "path", "dynamicLookup", "handle", "info"}, RDataFactory.COMPLETE_VECTOR);
         public static final String DLL_INFO_REFERENCE = "DLLInfoReference";
         private static final RStringVector INFO_REFERENCE_CLASS = RDataFactory.createStringVectorFromScalar(DLL_INFO_REFERENCE);
@@ -127,7 +125,7 @@ public class DLL {
         private boolean forceSymbols;
         private DotSymbol[][] nativeSymbols = new DotSymbol[NativeSymbolType.values().length][];
 
-        DLLInfo(String name, String path, boolean dynamicLookup, Object handle) {
+        private DLLInfo(String name, String path, boolean dynamicLookup, Object handle) {
             this.id = ID.getAndIncrement();
             this.name = name;
             this.path = path;
@@ -135,6 +133,12 @@ public class DLL {
             this.handle = handle;
         }
 
+        private static synchronized DLLInfo create(String name, String path, boolean dynamicLookup, Object handle) {
+            DLLInfo result = new DLLInfo(name, path, dynamicLookup, handle);
+            list.add(result);
+            return result;
+        }
+
         public void setNativeSymbols(int nstOrd, DotSymbol[] symbols) {
             nativeSymbols[nstOrd] = symbols;
         }
@@ -241,7 +245,7 @@ public class DLL {
         }
     }
 
-    public static DLLInfo getDLLInfoForId(int id) {
+    public static synchronized DLLInfo getDLLInfoForId(int id) {
         for (DLLInfo dllInfo : list) {
             if (dllInfo.id == id) {
                 return dllInfo;
@@ -270,8 +274,6 @@ public class DLL {
         }
     }
 
-    private static final Semaphore listCritical = new Semaphore(1, false);
-
     /*
      * There is no sense in throwing an RError if we fail to load/init a (default) package during
      * initial context initialization, as it is essentially fatal for any of the standard packages
@@ -281,43 +283,33 @@ public class DLL {
      */
 
     @TruffleBoundary
-    public static DLLInfo load(String path, boolean local, boolean now) throws DLLException {
+    public static synchronized DLLInfo load(String path, boolean local, boolean now) throws DLLException {
         String absPath = Utils.tildeExpand(path);
-        try {
-            listCritical.acquire();
-            for (DLLInfo dllInfo : list) {
-                if (dllInfo.path.equals(absPath)) {
-                    // already loaded
-                    return dllInfo;
-                }
-            }
-            File file = new File(absPath);
-            Object handle = RFFIFactory.getRFFI().getBaseRFFI().dlopen(absPath, local, now);
-            if (handle == null) {
-                String dlError = RFFIFactory.getRFFI().getBaseRFFI().dlerror();
-                if (RContext.isInitialContextInitialized()) {
-                    throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, dlError);
-                } else {
-                    throw Utils.fatalError("error loading default package: " + path + "\n" + dlError);
-                }
+        for (DLLInfo dllInfo : list) {
+            if (dllInfo.path.equals(absPath)) {
+                // already loaded
+                return dllInfo;
             }
-            String name = file.getName();
-            int dx = name.lastIndexOf('.');
-            if (dx > 0) {
-                name = name.substring(0, dx);
+        }
+        File file = new File(absPath);
+        Object handle = RFFIFactory.getRFFI().getBaseRFFI().dlopen(absPath, local, now);
+        if (handle == null) {
+            String dlError = RFFIFactory.getRFFI().getBaseRFFI().dlerror();
+            if (RContext.isInitialContextInitialized()) {
+                throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, dlError);
+            } else {
+                throw Utils.rSuicide("error loading default package: " + path + "\n" + dlError);
             }
-            DLLInfo result = new DLLInfo(name, absPath, true, handle);
-            list.add(result);
-            return result;
-        } catch (InterruptedException ex) {
-            throw RInternalError.shouldNotReachHere();
-        } finally {
-            listCritical.release();
         }
+        String name = file.getName();
+        int dx = name.lastIndexOf('.');
+        if (dx > 0) {
+            name = name.substring(0, dx);
+        }
+        return DLLInfo.create(name, absPath, true, handle);
     }
 
     private static final String R_INIT_PREFIX = "R_init_";
-    private static final Semaphore initCritical = new Semaphore(1, false);
 
     @TruffleBoundary
     public static DLLInfo loadPackageDLL(String path, boolean local, boolean now) throws DLLException {
@@ -326,8 +318,7 @@ public class DLL {
         String pkgInit = R_INIT_PREFIX + dllInfo.name;
         long initFunc = RFFIFactory.getRFFI().getBaseRFFI().dlsym(dllInfo.handle, pkgInit);
         if (initFunc != 0) {
-            try {
-                initCritical.acquire();
+            synchronized (DLL.class) {
                 try {
                     RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(initFunc, pkgInit, new Object[]{dllInfo});
                 } catch (ReturnException ex) {
@@ -338,41 +329,30 @@ public class DLL {
                     if (RContext.isInitialContextInitialized()) {
                         throw new DLLException(RError.Message.DLL_RINIT_ERROR);
                     } else {
-                        throw Utils.fatalError(RError.Message.DLL_RINIT_ERROR.message + " on default package: " + path);
+                        throw Utils.rSuicide(RError.Message.DLL_RINIT_ERROR.message + " on default package: " + path);
                     }
                 }
-            } catch (InterruptedException ex) {
-                throw RInternalError.shouldNotReachHere();
-            } finally {
-                initCritical.release();
             }
         }
         return dllInfo;
     }
 
     @TruffleBoundary
-    public static void unload(String path) throws DLLException {
+    public static synchronized void unload(String path) throws DLLException {
         String absPath = Utils.tildeExpand(path);
-        try {
-            listCritical.acquire();
-            for (DLLInfo info : list) {
-                if (info.path.equals(absPath)) {
-                    int rc = RFFIFactory.getRFFI().getBaseRFFI().dlclose(info.handle);
-                    if (rc != 0) {
-                        throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, "");
-                    }
-                    return;
+        for (DLLInfo info : list) {
+            if (info.path.equals(absPath)) {
+                int rc = RFFIFactory.getRFFI().getBaseRFFI().dlclose(info.handle);
+                if (rc != 0) {
+                    throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, "");
                 }
+                return;
             }
-        } catch (InterruptedException ex) {
-            throw RInternalError.shouldNotReachHere();
-        } finally {
-            listCritical.release();
         }
         throw new DLLException(RError.Message.DLL_NOT_LOADED, path);
     }
 
-    public static ArrayList<DLLInfo> getLoadedDLLs() {
+    public static synchronized ArrayList<DLLInfo> getLoadedDLLs() {
         ArrayList<DLLInfo> result = new ArrayList<>();
         for (DLLInfo dllInfo : list) {
             result.add(dllInfo);
@@ -455,49 +435,35 @@ public class DLL {
      *            {@code null})
      */
     @TruffleBoundary
-    public static long findSymbol(String name, String libName, RegisteredNativeSymbol rns) {
+    public static synchronized long findSymbol(String name, String libName, RegisteredNativeSymbol rns) {
         boolean all = libName == null || libName.length() == 0;
-        try {
-            listCritical.acquire();
-            for (DLLInfo dllInfo : list) {
-                if (dllInfo.forceSymbols) {
-                    continue;
-                }
-                if (all || dllInfo.name.equals(libName)) {
-                    long func = dlsym(dllInfo, name, rns);
-                    if (func != SYMBOL_NOT_FOUND) {
-                        if (rns != null) {
-                            rns.dllInfo = dllInfo;
-                        }
-                        return func;
+        for (DLLInfo dllInfo : list) {
+            if (dllInfo.forceSymbols) {
+                continue;
+            }
+            if (all || dllInfo.name.equals(libName)) {
+                long func = dlsym(dllInfo, name, rns);
+                if (func != SYMBOL_NOT_FOUND) {
+                    if (rns != null) {
+                        rns.dllInfo = dllInfo;
                     }
-                }
-                if (!all && dllInfo.name.equals(libName)) {
-                    return SYMBOL_NOT_FOUND;
+                    return func;
                 }
             }
-            return SYMBOL_NOT_FOUND;
-        } catch (InterruptedException ex) {
-            throw RInternalError.shouldNotReachHere();
-        } finally {
-            listCritical.release();
+            if (!all && dllInfo.name.equals(libName)) {
+                return SYMBOL_NOT_FOUND;
+            }
         }
+        return SYMBOL_NOT_FOUND;
     }
 
-    public static DLLInfo findLibrary(String name) {
-        try {
-            listCritical.acquire();
-            for (DLLInfo dllInfo : list) {
-                if (dllInfo.name.equals(name)) {
-                    return dllInfo;
-                }
+    public static synchronized DLLInfo findLibrary(String name) {
+        for (DLLInfo dllInfo : list) {
+            if (dllInfo.name.equals(name)) {
+                return dllInfo;
             }
-            return null;
-        } catch (InterruptedException ex) {
-            throw RInternalError.shouldNotReachHere();
-        } finally {
-            listCritical.release();
         }
+        return null;
     }
 
     @TruffleBoundary
@@ -527,4 +493,14 @@ public class DLL {
         dllInfo.forceSymbols = value == 0 ? false : true;
         return old;
     }
+
+    private static final String EMBEDDING = "(embedding)";
+
+    public static DLLInfo getEmbeddingDLLInfo() {
+        DLLInfo result = findLibrary(EMBEDDING);
+        if (result == null) {
+            result = DLLInfo.create(EMBEDDING, EMBEDDING, false, null);
+        }
+        return result;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/REmbedRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/REmbedRFFI.java
new file mode 100644
index 0000000000000000000000000000000000000000..0be0b85c6a17b0fea4698ddc758d4037ed86c956
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/REmbedRFFI.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+/**
+ * Function downcalls related to the embedded API.
+ */
+public interface REmbedRFFI {
+    void suicide(String x);
+
+    void cleanUp(int type, int x, int y);
+
+    String readConsole(String prompt);
+
+    void writeConsole(String x);
+
+    void writeErrConsole(String x);
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
index 11310d764670a760781c0d59c3a628b4c365c5d6..841567fef07f38e99e8b1554a47de817c8e0028b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -39,6 +39,7 @@ package com.oracle.truffle.r.runtime.ffi;
  * <li>{@link UserRngRFFI}: specific interface to user-supplied random number generator.</li>
  * <li>{@link PCRERFFI}: interface to PCRE library (Perl regexp).</li>
  * <li>{@link ZipRFFI}: interface to zip compression</li>
+ * <li>{@link REmbedRFFI}: interface to embedded support</li>
  * </ul>
  *
  * These interfaces may be implemented by one or more providers, specified either when the FastR
@@ -67,4 +68,6 @@ public interface RFFI {
 
     ZipRFFI getZipRFFI();
 
+    REmbedRFFI getREmbedRFFI();
+
 }
diff --git a/com.oracle.truffle.r.test.native/Makefile b/com.oracle.truffle.r.test.native/Makefile
index d764e42992ffedf7d4e641901334ea62953ca339..37c62d9a92a3bb060854303ab453afc9647cdf88 100644
--- a/com.oracle.truffle.r.test.native/Makefile
+++ b/com.oracle.truffle.r.test.native/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, 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
@@ -24,11 +24,18 @@
 .PHONY: all clean
 
 export TOPDIR = $(CURDIR)
+OSNAME := $(shell uname)
 
 all:
 	$(MAKE) -C urand
 	$(MAKE) -C packages
+ifneq ($(OSNAME), SunOS)
+	$(MAKE) -C embedded
+endif
 
 clean:
 	$(MAKE) -C urand clean
 	$(MAKE) -C packages clean
+ifneq ($(OSNAME), SunOS)
+	$(MAKE) -C embedded clean
+endif
diff --git a/com.oracle.truffle.r.test.native/embedded/Makefile b/com.oracle.truffle.r.test.native/embedded/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..6496998f45135262c414513b3faa700580e214a6
--- /dev/null
+++ b/com.oracle.truffle.r.test.native/embedded/Makefile
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2016, 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
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+ifeq ($(TOPDIR),)
+    TOPDIR = $(abspath ..)
+endif
+
+NATIVE_PROJECT = $(subst test.native,native,$(TOPDIR))
+ifneq ($(MAKECMDGOALS),clean)
+include $(NATIVE_PROJECT)/platform.mk
+endif
+
+OSNAME := $(shell uname)
+
+ifeq ($(OSNAME), Linux)
+  LD_FLAGS :=  -Wl,--unresolved-symbols=ignore-all
+else 
+  ifeq ($(OSNAME), SunOS)
+    LD_FLAGS := -z lazyload
+  endif
+endif
+
+FASTR_LIB_DIR = $(abspath ../../lib)
+
+
+.PHONY: all clean
+
+OBJ = lib
+SRC = src
+C_SOURCES := $(wildcard $(SRC)/*.c)
+C_OBJECTS := $(subst $(SRC),$(OBJ),$(C_SOURCES:.c=.o))
+
+
+INCLUDE_DIR := $(NATIVE_PROJECT)/include
+
+all: $(OBJ)/main
+
+$(OBJ)/main: | $(OBJ)
+
+$(OBJ):
+	mkdir -p $(OBJ)
+
+
+$(OBJ)/main: $(SRC)/main.c
+	$(CC) $(CFLAGS) -I$(INCLUDE_DIR) $< -o $(OBJ)/main -L $(FASTR_LIB_DIR) -ldl -lR $(LD_FLAGS)
+
+clean:
+	rm -rf $(OBJ)
diff --git a/com.oracle.truffle.r.test.native/embedded/src/main.c b/com.oracle.truffle.r.test.native/embedded/src/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a01de741f8bfa562febb21098caafb6918bfad9
--- /dev/null
+++ b/com.oracle.truffle.r.test.native/embedded/src/main.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// A simple test program for FastR embedded mode.
+// compile with "gcc -I include main.c -ldl
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <sys/utsname.h>
+#include <string.h>
+#define R_INTERFACE_PTRS 1
+#include <Rinterface.h>
+#include <Rembedded.h>
+#include <R_ext/RStartup.h>
+#include <R_ext/Rdynload.h>
+
+
+void (*ptr_stdR_CleanUp)(SA_TYPE, int, int);
+void (*ptr_stdR_Suicide)(const char *);
+
+void testR_CleanUp(SA_TYPE x, int y, int z) {
+	printf("test Cleanup\n");
+	(ptr_stdR_CleanUp)(x, y, z);
+}
+
+void testR_Suicide(const char *msg) {
+	printf("testR_Suicide: %s\n",msg);
+	(ptr_stdR_Suicide(msg));
+}
+
+int  testR_ReadConsole(const char *prompt, unsigned char *buf, int len, int h) {
+	fputs(prompt, stdout);
+	fflush(stdout); /* make sure prompt is output */
+	if (fgets((char *)buf, len, stdin) == NULL) {
+		return 0;
+	} else {
+	    return 1;
+	}
+}
+
+void testR_WriteConsole(const char *buf, int len) {
+    printf("%s", buf);
+    fflush(stdout);
+}
+
+int main(int argc, char **argv) {
+	char *r_home = getenv("R_HOME");
+	if (r_home == NULL) {
+		printf("R_HOME must be set\n");
+		exit(1);
+	}
+	Rf_initialize_R(argc, argv);
+	structRstart rp;
+	Rstart Rp = &rp;
+	R_DefParams(Rp);
+	Rp->SaveAction = SA_SAVEASK;
+	R_SetParams(Rp);
+	ptr_stdR_CleanUp = ptr_R_CleanUp;
+	ptr_R_CleanUp = &testR_CleanUp;
+	ptr_stdR_Suicide = ptr_R_Suicide;
+	ptr_R_Suicide = &testR_Suicide;
+	ptr_R_ReadConsole = &testR_ReadConsole;
+	ptr_R_WriteConsole = &testR_WriteConsole;
+	DllInfo *eDllInfo = R_getEmbeddingDllInfo();
+	Rf_mainloop();
+	Rf_endEmbeddedR(0);
+}
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
index 4a14d3cf87f8cf271c400ef58edf45bce32f29c8..767a8c3cbcd9b43a42eed4a917dcaba28353adaf 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
@@ -46,6 +46,31 @@ rffi.invoke12 <- function() {
 	.Call("invoke12", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, PACKAGE = "testrffi")
 }
 
+rffi.interactive <- function() {
+	.Call("interactive", PACKAGE = "testrffi");
+}
+
+rffi.tryEval <- function(expr, env) {
+	.Call("tryEval", expr, env, PACKAGE = "testrffi")
+}
+
+rffi.rhome_dir <- function() {
+	.Call("rHomeDir", PACKAGE = "testrffi")
+}
+
+rffi.upcalled <- function(v) {
+	gc()
+	.Call("nestedCall2", PACKAGE = "testrffi", v)
+}
+
+rffi.nested.call1 <- function() {
+	upcall <- quote(rffi.upcalled(v))
+	v <- c(10L, 20L, 30L)
+	env <- new.env()
+	assign("v", v, env)
+	.Call("nestedCall1", PACKAGE = "testrffi", upcall, env)
+}
+
 rffi.r_home <- function() {
 	.Call("r_home", PACKAGE = "testrffi")
 }
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
index 8e367674aa1c85c39440b52b3cba7ecdc1d613c2..0d6d6674ffcd3812a1b859494df934aebf536b1c 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
@@ -27,6 +27,7 @@
 #include <Rdefines.h>
 #include <Rinterface.h>
 #include <Rinternals.h>
+#include <Rinterface.h>
 
 void dotCModifiedArguments(int* len, int* idata, double* rdata, int* ldata) {
     for (int i = 0; i < len[0]; i++) {
@@ -151,6 +152,68 @@ SEXP invoke12(SEXP a1, SEXP a2, SEXP a3, SEXP a4, SEXP a5, SEXP a6, SEXP a7, SEX
 	return a12;
 }
 
+SEXP interactive(void) {
+	return ScalarLogical(R_Interactive);
+}
+
+SEXP tryEval(SEXP expr, SEXP env) {
+	int error;
+	SEXP r = R_tryEval(expr, env, &error);
+	SEXP v;
+	PROTECT(v = allocVector(VECSXP, 2));
+	if (error) {
+		r = R_NilValue;
+	}
+	SET_VECTOR_ELT(v, 0, r);
+	SET_VECTOR_ELT(v, 1, ScalarLogical(error));
+	UNPROTECT(1);
+	return v;
+}
+
+SEXP rHomeDir() {
+	char *dir = R_HomeDir();
+	return ScalarString(mkChar(dir));
+}
+
+SEXP nestedCall1(SEXP upcall, SEXP env) {
+	SEXP vec;
+	PROTECT(vec = allocVector(INTSXP, 10));
+	int *vecstar = INTEGER(vec);
+	for (int i = 0; i < 10; i++) {
+		vecstar[i] = i + 1;
+	}
+	SEXP upcallResult = tryEval(upcall, env);
+	int *vecstar2 = INTEGER(vec);
+	int ok = vecstar == vecstar2;
+	if (ok) {
+		for (int i = 0; i < 10; i++) {
+			if (vecstar[i] != i + 1) {
+				ok = 0;
+				break;
+			}
+		}
+	}
+	SEXP result;
+	PROTECT(result = allocVector(VECSXP, 2));
+	SET_VECTOR_ELT(result, 0, upcallResult);
+	SET_VECTOR_ELT(result, 1, ScalarLogical(ok));
+	UNPROTECT(2);
+	return result;
+}
+
+SEXP nestedCall2(SEXP v) {
+	SEXP sumVec;
+	PROTECT(sumVec = allocVector(INTSXP, 1));
+	int len = Rf_length(v);
+	int sum = 0;
+	for (int i = 0; i < len; i++) {
+		sum += INTEGER(v)[i];
+	}
+	INTEGER(sumVec)[0] = sum;
+	UNPROTECT(1);
+	return sumVec;
+}
+
 SEXP r_home(void) {
 	return mkString(R_Home);
 }
@@ -195,6 +258,3 @@ SEXP iterate_iptr(SEXP x) {
     UNPROTECT(1);
     return v;
 }
-
-
-
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 478ac346fb42ee04ab52e6b90a6cdbed069428ef..8bca99d985bc4f7cde543a0edf8814d21ddfa77a 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -45475,6 +45475,33 @@ character(0)
 [1] "a" "h" "o" "j"
 
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_strsplit.testStrSplit
+#{ strsplit("abc", ".", fixed = FALSE, perl=FALSE) }
+[[1]]
+[1] "" "" ""
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_strsplit.testStrSplit
+#{ strsplit("abc", ".", fixed = FALSE, perl=TRUE) }
+[[1]]
+[1] "" "" ""
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_strsplit.testStrSplit
+#{ strsplit("abc", ".", fixed = TRUE, perl=FALSE) }
+[[1]]
+[1] "abc"
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_strsplit.testStrSplit
+#{ strsplit("abc", ".", fixed = TRUE, perl=TRUE) }
+[[1]]
+[1] "abc"
+
+Warning message:
+In strsplit("abc", ".", fixed = TRUE, perl = TRUE) :
+  argument 'perl = TRUE' will be ignored
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_strsplit.testStrSplit
 #{ strsplit("ahoj", split="") [[c(1,2)]] }
 [1] "h"
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strsplit.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strsplit.java
index 9558fb6b46e8ef44293d84233dda7282676bfdf4..5b31458322853d4904ca93253dbf44312afb0f6e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strsplit.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strsplit.java
@@ -110,5 +110,10 @@ public class TestBuiltin_strsplit extends TestBase {
         assertEval("{ strsplit( c(\"helloh\", \"hi\"), c(\"h\",\"\")) }");
         assertEval("{ strsplit(\"ahoj\", split=\"\") [[c(1,2)]] }");
         assertEval("{ strsplit(\"a,h,o,j\", split=\",\") }");
+        assertEval("{ strsplit(\"abc\", \".\", fixed = TRUE, perl=FALSE) }");
+        // Warning text formats differently
+        assertEval(Ignored.OutputFormatting, "{ strsplit(\"abc\", \".\", fixed = TRUE, perl=TRUE) }");
+        assertEval("{ strsplit(\"abc\", \".\", fixed = FALSE, perl=FALSE) }");
+        assertEval("{ strsplit(\"abc\", \".\", fixed = FALSE, perl=TRUE) }");
     }
 }
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 b4720533ce8e7378ebe9df32d4c73f6cc2ccf59c..7a2e66057d0a81aba32d486120cc75937c8537f1 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
@@ -38,6 +38,7 @@ import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.ContextInfo;
@@ -115,11 +116,6 @@ public final class FastRSession implements RSession {
             buffer.delete(0, buffer.length());
         }
 
-        @Override
-        public int getWidth() {
-            return RContext.CONSOLE_WIDTH;
-        }
-
         @Override
         public String getInputDescription() {
             return "<test input>";
@@ -155,15 +151,15 @@ public final class FastRSession implements RSession {
     }
 
     public ContextInfo createContextInfo(ContextKind contextKind) {
-        RCmdOptions options = RCmdOptions.parseArguments(Client.RSCRIPT, new String[0]);
-        return ContextInfo.create(options, contextKind, mainContext, consoleHandler, TimeZone.getTimeZone("CET"));
+        RStartParams params = new RStartParams(RCmdOptions.parseArguments(Client.RSCRIPT, new String[0], false), false);
+        return ContextInfo.create(params, contextKind, mainContext, consoleHandler, TimeZone.getTimeZone("CET"));
     }
 
     private FastRSession() {
         consoleHandler = new TestConsoleHandler();
         try {
-            RCmdOptions options = RCmdOptions.parseArguments(Client.RSCRIPT, new String[]{"--no-restore"});
-            ContextInfo info = ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler);
+            RStartParams params = new RStartParams(RCmdOptions.parseArguments(Client.RSCRIPT, new String[]{"--no-restore"}, false), false);
+            ContextInfo info = ContextInfo.create(params, ContextKind.SHARE_NOTHING, null, consoleHandler);
             main = info.createVM();
             try {
                 mainContext = main.eval(GET_CONTEXT).as(RContext.class);
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index d00961fd8b0f297a0227a0f693c8284c0eda0c20..573f4ba7708d8c65544061cb755aada2ce29520a 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -56,6 +56,7 @@ com.oracle.truffle.r.native/fficall/src/common/arithmetic_fastr.c,gnu_r_gentlema
 com.oracle.truffle.r.native/fficall/src/common/coerce_fastr.c,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.native/fficall/src/common/errors_fastr.c,gnu_r.core.copyright
 com.oracle.truffle.r.native/fficall/src/common/inlined_fastr.c,gnu_r_gentleman_ihaka.copyright
+com.oracle.truffle.r.native/fficall/src/common/localecharset_fastr.c,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/common/print_fastr.c,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.native/fficall/src/common/printutils_fastr.c,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.native/fficall/src/common/sys_fastr.c,gnu_r.copyright
@@ -75,6 +76,7 @@ com.oracle.truffle.r.native/fficall/src/include/rlocale.h,gnu_r_gentleman_ihaka.
 com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/jni/Memory.c,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/jni/Rdynload_fastr.c,gnu_r.copyright
+com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c,gnu_r.copyright
 com.oracle.truffle.r.native/include/src/libintl.h,no.copyright
 com.oracle.truffle.r.native/library/base/src/registration.c,no.copyright
 com.oracle.truffle.r.native/library/grDevices/src/gzio.c,gnu_r_gentleman_ihaka.copyright
@@ -105,6 +107,7 @@ com.oracle.truffle.r.native/library/tools/src/gramRd.c,no.copyright
 com.oracle.truffle.r.native/library/tools/src/tools_dummy.c,no.copyright
 com.oracle.truffle.r.native/library/utils/src/utils_dummy.c,no.copyright
 com.oracle.truffle.r.native/run/R.sh,oracle_bash.copyright
+com.oracle.truffle.r.native/run/Rclasspath.sh,oracle_bash.copyright
 com.oracle.truffle.r.native/run/Rscript_exec.sh,oracle_bash.copyright
 com.oracle.truffle.r.native/run/Rscript.sh,oracle_bash.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java,gnu_r.copyright
@@ -149,6 +152,7 @@ com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/L
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java,gnu_r_gentleman_ihaka.copyright
+com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java,purdue.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java,gnu_r_gentleman_ihaka.copyright
@@ -189,6 +193,8 @@ com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.jav
 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java,purdue.copyright
 com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g,purdue.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSrcref.java,gnu_r.copyright
+com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RStartParams.java,gnu_r.copyright
+com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypedValue.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java,gnu_r.copyright
 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java,gnu_r.copyright
diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py
index db21ce41598ff85a610aedebff95f19fe7ac4b42..dd65727a8202fb78c7388cd8e15755401064208c 100644
--- a/mx.fastr/mx_fastr.py
+++ b/mx.fastr/mx_fastr.py
@@ -46,7 +46,9 @@ _r_command_project = 'com.oracle.truffle.r.engine'
 _repl_command = 'com.oracle.truffle.tools.debug.shell.client.SimpleREPLClient'
 _command_class_dict = {'r': _r_command_project + ".shell.RCommand",
                        'rscript': _r_command_project + ".shell.RscriptCommand",
-                        'rrepl': _repl_command}
+                        'rrepl': _repl_command,
+                        'rembed': _r_command_project + ".shell.REmbedded",
+                    }
 # benchmarking support
 def r_path():
     return join(_fastr_suite.dir, 'bin', 'R')
@@ -99,6 +101,9 @@ def do_run_r(args, command, extraVmArgs=None, jdk=None, **kwargs):
         vmArgs.append(_command_class_dict[command.lower()])
     return mx.run_java(vmArgs + args, jdk=jdk, **kwargs)
 
+def r_classpath(args):
+    print mx.classpath(_r_command_project)
+
 def _sanitize_vmArgs(jdk, vmArgs):
     '''
     jdk dependent analysis of vmArgs to remove those that are not appropriate for the
@@ -214,6 +219,9 @@ def rrepl(args, nonZeroIsFatal=True, extraVmArgs=None):
     '''run R repl'''
     run_r(args, 'rrepl')
 
+def rembed(args, nonZeroIsFatal=True, extraVmArgs=None):
+    run_r(args, 'rembed')
+
 def _fastr_gate_runner(args, tasks):
     # Until fixed, we call Checkstyle here and limit to primary
     with mx_gate.Task('Checkstyle check', tasks) as t:
@@ -504,8 +512,10 @@ _commands = {
     'rcmplib' : [rcmplib, ['options']],
     'pkgtest' : [mx_fastr_pkgs.pkgtest, ['options']],
     'rrepl' : [rrepl, '[options]'],
+    'rembed' : [rembed, '[options]'],
     'installpkgs' : [installpkgs, '[options]'],
     'installcran' : [installpkgs, '[options]'],
+    'r-cp' : [r_classpath, '[options]'],
     }
 
 mx.update_commands(_fastr_suite, _commands)