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 60a35920fe752bd1d1c47db79bd5fdd29af4cb5b..edd3314671962989ab151741e632bf6caad0b808 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
@@ -78,15 +78,34 @@ public class RCommand {
     // CheckStyle: stop system..print check
 
     public static void main(String[] args) {
-        RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args);
-        options.printHelpAndVersion();
-        ContextInfo info = createContextInfoFromCommandLine(options);
+        PolyglotEngine vm = createPolyglotEngine(args);
         // never returns
-        readEvalPrint(info);
+        readEvalPrint(vm);
         throw RInternalError.shouldNotReachHere();
     }
 
-    static ContextInfo createContextInfoFromCommandLine(RCmdOptions options) {
+    /**
+     * This exists as a separate method to support the Rembedded API.
+     */
+    static PolyglotEngine createPolyglotEngine(String[] args) {
+        RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args);
+        options.printHelpAndVersion();
+        PolyglotEngine vm = createContextInfoFromCommandLine(options);
+        return vm;
+    }
+
+    /**
+     * Creates the PolyglotEngine and initializes it. Called from native code when FastR is
+     * embedded.
+     */
+    static PolyglotEngine initialize(String[] args) {
+        PolyglotEngine vm = createPolyglotEngine(args);
+        // Any expression will do to initialize the engine.
+        doEcho(vm);
+        return vm;
+    }
+
+    static PolyglotEngine createContextInfoFromCommandLine(RCmdOptions options) {
         if (options.getBoolean(SLAVE)) {
             options.setValue(QUIET, true);
             options.setValue(NO_SAVE, true);
@@ -170,7 +189,7 @@ public class RCommand {
                 consoleHandler = new DefaultConsoleHandler(consoleInput, consoleOutput);
             }
         }
-        return ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler);
+        return ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler).apply(PolyglotEngine.newBuilder()).build();
     }
 
     private static final Source GET_ECHO = Source.fromText("invisible(getOption('echo'))", RInternalSourceDescriptions.GET_ECHO).withMimeType(TruffleRLanguage.MIME);
@@ -187,9 +206,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.apply(PolyglotEngine.newBuilder()).build();
-        ConsoleHandler consoleHandler = info.getConsoleHandler();
+    static void readEvalPrint(PolyglotEngine vm) {
+        ConsoleHandler consoleHandler = getContextInfo(vm).getConsoleHandler();
         Source source = Source.fromAppendableText(consoleHandler.getInputDescription());
         try {
             // console.println("initialize time: " + (System.currentTimeMillis() - start));
@@ -280,6 +298,14 @@ public class RCommand {
         }
     }
 
+    private static ContextInfo getContextInfo(PolyglotEngine vm) {
+        try {
+            return (ContextInfo) vm.findGlobalSymbol(ContextInfo.GLOBAL_SYMBOL).get();
+        } catch (IOException ex) {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
     private static boolean doEcho(PolyglotEngine vm) {
         PolyglotEngine.Value echoValue;
         try {
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c59c0dfb2a1dc371022c9ff4004a158b12a32b2
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java
@@ -0,0 +1,75 @@
+/*
+ * 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.engine.shell;
+
+/**
+ * Support for Rembedded. Defines startup parameters that can be customized by embedding apps.
+ */
+public class RStartParams {
+
+    public enum SA_TYPE {
+        NORESTORE,
+        RESTORE,
+        DEFAULT,
+        NOSAVE,
+        SAVE,
+        SAVEASK,
+        SUICIDE
+    }
+
+    private boolean quiet;
+    private boolean slave;
+    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;
+
+    private static RStartParams active;
+
+    private RStartParams() {
+
+    }
+
+    /**
+     * Only upcalled from native code.
+     */
+    public RStartParams(boolean quiet, boolean slave, boolean interactive, boolean verbose, boolean loadSiteFile,
+                    boolean loadInitFile, boolean debugInitFile, int restoreAction,
+                    int saveAction, boolean noRenviron) {
+        this.quiet = quiet;
+        this.slave = slave;
+        this.interactive = interactive;
+        this.verbose = verbose;
+        this.loadSiteFile = loadSiteFile;
+        this.loadInitFile = loadInitFile;
+        this.debugInitFile = debugInitFile;
+        this.restoreAction = SA_TYPE.values()[restoreAction];
+        this.saveAction = SA_TYPE.values()[saveAction];
+        this.noRenviron = noRenviron;
+    }
+
+    public static RStartParams getActive() {
+        if (active == null) {
+            active = new RStartParams();
+        }
+        return active;
+    }
+
+    public static void setParams(RStartParams rs) {
+        active = rs;
+    }
+
+}
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..33108b010f1203946be2f97259c337e5c2e67254 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
@@ -101,9 +101,9 @@ public class RscriptCommand {
         // Handle --help and --version specially, as they exit.
         RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.RSCRIPT, args);
         preprocessRScriptOptions(options);
-        ContextInfo info = RCommand.createContextInfoFromCommandLine(options);
+        PolyglotEngine vm = RCommand.createContextInfoFromCommandLine(options);
         // never returns
-        RCommand.readEvalPrint(info);
+        RCommand.readEvalPrint(vm);
         throw RInternalError.shouldNotReachHere();
     }
 
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
index 0b78deb4265ac2eea47ae6ae315953e63296944b..d071862f1cd4b368754dcf6699eaeab6caf8194a 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
@@ -1,58 +1,72 @@
 /*
- * Copyright (c) 2016, 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-2015, The R Core Team
+ * Copyright (c) 2003, The R Foundation
+ * Copyright (c) 2016, 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.
  */
-#include <rffiutils.h>
 #include <dlfcn.h>
 #include <sys/utsname.h>
+#include <rffiutils.h>
+#include <R_ext/RStartup.h>
+
 
 static JavaVM *javaVM;
+static JNIEnv *jniEnv;
+static jobject engine;
+static int initialized = 0;
 
-int Rf_initEmbeddedR(int argc, char *argv[]) {
+static jclass rcommandClass;
+static jclass rStartParamsClass;
+
+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) {
+		printf("Rf_initialize_R: cannot dlopen %s: %s\n", libpath, dlerror());
+		exit(1);
+	}
+	return handle;
+}
+
+int Rf_initialize_R(int argc, char *argv[]) {
+	if (initialized) {
+		fprintf(stderr, "%s", "R is already initialized\n");
+		exit(1);
+	}
 	struct utsname utsname;
 	uname(&utsname);
-	printf("is: %s\n", utsname.sysname);
-	char *jvmlib_path = malloc(256);
-	char *fastr_java_vm = getenv("FASTR_JAVA_VM");
-	if (fastr_java_vm == NULL) {
-		char *java_home = getenv("JAVA_HOME");
-		if (java_home == NULL) {
-			printf("Rf_initEmbeddedR: can't find a Java VM");
-			exit(1);
-		}
-		strcpy(jvmlib_path, java_home);
-		if (strcmp(utsname.sysname, "Linux")) {
-			strcat(jvmlib_path, "/jre/lib/amd64/server/libjvm.so");
-		} else if (strcmp(utsname.sysname, "Darwin")) {
-			strcat(jvmlib_path, "/jre/lib/server/libjvm.dylib");
-		} else {
-			printf("unsupported OS: %s\n"utsname.sysname);
-			exit(1);
-		}
+	char jvmlib_path[256];
+	char *java_home = getenv("JAVA_HOME");
+	if (java_home == NULL) {
+		printf("Rf_initialize_R: can't find JAVA_HOME");
+		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 {
-		strcpy(jvmlib_path, fastr_java_vm);
+		printf("unsupported OS: %s\n", utsname.sysname);
+		exit(1);
 	}
-	void *vm_handle = dlopen(jvmlib_path, RTLD_GLOBAL | RTLD_NOW);
-	if (vm_handle == NULL) {
-		printf("Rf_initEmbeddedR: cannot dlopen %s: %s\n", jvmlib_path, dlerror());
+	void *vm_handle = dlopen_jvmlib(jvmlib_path);
+	JNI_CreateJavaVMFunc createJavaVMFunc = (JNI_CreateJavaVMFunc) dlsym(vm_handle, "JNI_CreateJavaVM");
+	if (createJavaVMFunc == NULL) {
+		printf("Rf_initialize_R: cannot find JNI_CreateJavaVM\n");
 		exit(1);
 	}
 
@@ -60,7 +74,7 @@ int Rf_initEmbeddedR(int argc, char *argv[]) {
 	JavaVMOption vm_options[1];
 	char *vm_cp = getenv("FASTR_CLASSPATH");
 	if (vm_cp == NULL) {
-		printf("Rf_initEmbeddedR: FASTR_CLASSPATH env var not set\n");
+		printf("Rf_initialize_R: FASTR_CLASSPATH env var not set\n");
 		exit(1);
 	}
 	int cplen = (int) strlen(vm_cp);
@@ -78,24 +92,113 @@ int Rf_initEmbeddedR(int argc, char *argv[]) {
 	vm_args.options = vm_options;
 	vm_args.ignoreUnrecognized = JNI_TRUE;
 
-	JNIEnv *jniEnv;
-	long flag = JNI_CreateJavaVM(&javaVM, (void**)
+	jint flag = (*createJavaVMFunc)(&javaVM, (void**)
 			&jniEnv, &vm_args);
 	if (flag == JNI_ERR) {
-		printf("Rf_initEmbeddedR: error creating VM, exiting...\n");
+		printf("Rf_initEmbeddedR: error creating Java VM, exiting...\n");
 		return 1;
 	}
-	jclass mainClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/RCommand");
+
+	rcommandClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/RCommand");
+	rStartParamsClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/RStartParams");
 	jclass stringClass = checkFindClass(jniEnv, "java/lang/String");
-	jmethodID mainMethod = checkGetMethodID(jniEnv, mainClass, "main", "([Ljava/lang/String;)V", 1);
+	jmethodID initializeMethod = checkGetMethodID(jniEnv, rcommandClass, "initialize",
+			"([Ljava/lang/String;)Lcom/oracle/truffle/api/vm/PolyglotEngine;", 1);
 	int argLength = 0;
 	jobjectArray argsArray = (*jniEnv)->NewObjectArray(jniEnv, argLength, stringClass, NULL);
 
-	(*jniEnv)->CallStaticVoidMethod(jniEnv, mainClass, mainMethod, argsArray);
+	engine = checkRef(jniEnv, (*jniEnv)->CallStaticObjectMethod(jniEnv, rcommandClass, initializeMethod, argsArray));
+	initialized++;
 	return 0;
 }
 
+void setup_Rmainloop(void) {
+	// In GnuR R_initialize_R and setup_Rmainloop do different things.
+	// In FastR we don't (yet?) have the distinction, so there is nothing more to do here
+}
+
+void R_DefParams(Rstart rs) {
+//	jmethodID getActiveMethod = checkGetMethodId(jniEnv, rStartParamsClass, "getActive", "(V)Lcom/oracle/truffle/r/engine/shell/RStartParams;", 1);
+    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) {
+	jmethodID setParamsMethodID = checkGetMethodID(jniEnv, rStartParamsClass, "setParams", "(Lcom/oracle/truffle/r/engine/shell/RStartParams;)V", 1);
+	jmethodID consMethodID = checkGetMethodID(jniEnv, rStartParamsClass, "<init>", "(ZZZZZZZIIZ)V", 0);
+	jobject javaRSParams = (*jniEnv)->NewObject(jniEnv, rStartParamsClass, consMethodID, rs->R_Quiet, rs->R_Slave, rs->R_Interactive,
+			rs->R_Verbose, rs->LoadSiteFile, rs->LoadInitFile, rs->DebugInitFile,
+			rs->RestoreAction, rs->SaveAction, rs->NoRenviron);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, rStartParamsClass, setParamsMethodID, javaRSParams);
+}
+
+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
 }
+
+void Rf_mainloop(void) {
+	jmethodID readEvalPrintMethod = checkGetMethodID(jniEnv, rcommandClass, "readEvalPrint", "(Lcom/oracle/truffle/api/vm/PolyglotEngine;)V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, rcommandClass, readEvalPrintMethod, engine);
+}
+
+// function ptrs that can be assigned by an embedded client to change behavior
+void (*ptr_R_Suicide)(const char *);
+void (*ptr_R_ShowMessage)(const char *);
+int  (*ptr_R_ReadConsole)(const char *, unsigned char *, int, int);
+void (*ptr_R_WriteConsole)(const char *, int);
+void (*ptr_R_WriteConsoleEx)(const char *, int, int);
+void (*ptr_R_ResetConsole)(void);
+void (*ptr_R_FlushConsole)(void);
+void (*ptr_R_ClearerrConsole)(void);
+void (*ptr_R_Busy)(int);
+void (*ptr_R_CleanUp)(SA_TYPE, int, int);
+int  (*ptr_R_ShowFiles)(int, const char **, const char **,
+			       const char *, Rboolean, const char *);
+int  (*ptr_R_ChooseFile)(int, char *, int);
+int  (*ptr_R_EditFile)(const char *);
+void (*ptr_R_loadhistory)(SEXP, SEXP, SEXP, SEXP);
+void (*ptr_R_savehistory)(SEXP, SEXP, SEXP, SEXP);
+void (*ptr_R_addhistory)(SEXP, SEXP, SEXP, SEXP);
+
+int  (*ptr_R_EditFiles)(int, const char **, const char **, const char *);
+
+SEXP (*ptr_do_selectlist)(SEXP, SEXP, SEXP, SEXP);
+SEXP (*ptr_do_dataentry)(SEXP, SEXP, SEXP, SEXP);
+SEXP (*ptr_do_dataviewer)(SEXP, SEXP, SEXP, SEXP);
+void (*ptr_R_ProcessEvents)();
+
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 e725f80386447912401b2a090425d39c93e1a23e..632570262291c58849151f99fdea3233aebf44f4 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
  * 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();
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index e852287e55fedbb8fd458bb6fb83bca3f8a59999..bac61dc04dec6fd5d5d85ab667d32a878d80a5de 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -1,3 +1,4 @@
+com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RStartParams.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/BaseGraphicsSystem.java,gnu_r_graphics.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/AbstractGraphicsSystem.java,gnu_r_graphics.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/core/drawables/CoordinatesDrawableObject.java,gnu_r_graphics.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