diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java
index afb26eabdb73aa56037db7e9ea2fe1ad6d31b6dc..952f2069c81fd667fd8b41463adab8bbb2e737b2 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/REmbedded.java
@@ -71,7 +71,7 @@ public class REmbedded {
      * 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 void initializeR(String[] args) {
+    private static void initializeR(String[] args, boolean initMainLoop) {
         assert context == null;
         RContext.setEmbedded();
         RCmdOptions options = RCmdOptions.parseArguments(RCmdOptions.Client.R, args, false);
@@ -86,6 +86,14 @@ public class REmbedded {
         context = Context.newBuilder().allowHostAccess(true).arguments("R", options.getArguments()).in(input).out(stdOut).err(stdErr).build();
         consoleHandler.setContext(context);
         context.eval(INIT);
+
+        if (initMainLoop) {
+            context.enter();
+            RContext ctx = RContext.getInstance();
+            ctx.completeEmbeddedInitialization();
+            ctx.getRFFI().initializeEmbedded(ctx);
+            // stay in the context TODO should we?
+        }
     }
 
     /**
@@ -110,12 +118,10 @@ public class REmbedded {
      */
     private static final Source INIT = Source.newBuilder("R", "1", "<embedded>").buildLiteral();
 
-    /**
-     * GnuR distinguishes {@code setup_Rmainloop} and {@code run_Rmainloop}. Currently we don't have
-     * the equivalent separation in FastR.
-     */
-    private static void setupRmainloop() {
-        // nothing to do
+    private static void endRmainloop(int status) {
+        context.leave();
+        context.close();
+        Utils.systemExit(status);
     }
 
     /**
@@ -124,7 +130,9 @@ public class REmbedded {
      */
     private static void runRmainloop() {
         context.enter();
-        RContext.getInstance().completeEmbeddedInitialization();
+        RContext ctx = RContext.getInstance();
+        ctx.completeEmbeddedInitialization();
+        ctx.getRFFI().initializeEmbedded(ctx);
         int status = RCommand.readEvalPrint(context, consoleHandler);
         context.leave();
         context.close();
@@ -135,8 +143,7 @@ public class REmbedded {
      * Testing vehicle, emulates a native upcall.
      */
     public static void main(String[] args) {
-        initializeR(args);
-        setupRmainloop();
+        initializeR(args, false);
         runRmainloop();
     }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
index 13eb6601ce8a4908d412362f3b9261621aa06d2d..3646e3f426ded191df575aff92e8b05f42ab2cc8 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
@@ -35,6 +35,7 @@ import java.util.List;
 import java.util.Set;
 
 import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.ForeignAccess;
@@ -140,6 +141,7 @@ public final class Managed_DownCallNodeFactory extends DownCallNodeFactory {
                 public CallTarget accessExecute(int argumentsLength) {
                     return Truffle.getRuntime().createCallTarget(new RootNode(null) {
                         @Override
+                        @TruffleBoundary
                         public Object execute(VirtualFrame frame) {
                             NativeCharArray templateBytes = (NativeCharArray) ForeignAccess.getArguments(frame).get(0);
                             String template = new String(templateBytes.getValue(), 0, templateBytes.getValue().length - 1);
@@ -191,6 +193,7 @@ public final class Managed_DownCallNodeFactory extends DownCallNodeFactory {
                 public CallTarget accessExecute(int argumentsLength) {
                     return Truffle.getRuntime().createCallTarget(new RootNode(null) {
                         @Override
+                        @TruffleBoundary
                         public Object execute(VirtualFrame frame) {
                             NativeCharArray buffer = (NativeCharArray) ForeignAccess.getArguments(frame).get(0);
                             byte[] bytes = Paths.get(".").toAbsolutePath().normalize().toString().getBytes();
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java
index 7b4c1ecec2669cd03be24e4aa23852b22db14b1b..b83771cec9b0c6885632d2bcc28f76b31f7ccfa7 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java
@@ -196,6 +196,11 @@ final class TruffleNFI_Context extends RFFIContext {
         }
     }
 
+    @Override
+    public void initializeEmbedded(RContext context) {
+        pushCallbacks();
+    }
+
     @TruffleBoundary
     private long initCallbacksAddress() {
         // get the address of the native thread local
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
index 2ee67837291d22f7397d77cd232ddf33f0f8de98..001cdcd36e7696e20fc4fac4b948fb187a68ae95 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
@@ -44,116 +44,90 @@ 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;
-}
-
-// --------------------
-// JNI helpers
-
-static JNIEnv* getEnv() {
-    return jniEnv;
-}
-
-static jmethodID checkGetMethodID(JNIEnv *env, jclass klass, const char *name, const char *sig, int isStatic) {
-    jmethodID methodID = isStatic ? (*env)->GetStaticMethodID(env, klass, name, sig) : (*env)->GetMethodID(env, klass, name, sig);
-    if (methodID == NULL) {
-        char buf[1024];
-        strcpy(buf, "failed to find ");
-        strcat(buf, isStatic ? "static" : "instance");
-        strcat(buf, " method ");
-        strcat(buf, name);
-        strcat(buf, "(");
-        strcat(buf, sig);
-        strcat(buf, ")");
-        (*env)->FatalError(env, buf);
-    }
-    return methodID;
-}
+int R_wait_usec;    // TODO: necessary to resolve externals? otherwise dead code
 
-jclass checkFindClass(JNIEnv *env, const char *name) {
-    jclass klass = (*env)->FindClass(env, name);
-    if (klass == NULL) {
-        char buf[1024];
-        strcpy(buf, "failed to find class ");
-        strcat(buf, name);
-        strcat(buf, ".\nDid you set R_HOME to the correct location?");
-        (*env)->FatalError(env, buf);
-    }
-    return (*env)->NewGlobalRef(env, klass);
-}
+typedef jint (JNICALL *JNI_CreateJavaVMFunc)(JavaVM **pvm, void **penv, void *args);
 
 
-// ---------------------
-// UpCalls
+// ------------------------------------------------------
+// Forward declarations of static helper functions
 
-// IDE and tools up-calls
+static void setupOverrides(void);
 
-CTXT R_getGlobalFunctionContext() {
-    return ((call_R_getGlobalFunctionContext) callbacks[R_getGlobalFunctionContext_x])();
-}
+static void *dlopen_jvmlib(char *libpath);
+static JNIEnv* getEnv();
+static jmethodID checkGetMethodID(JNIEnv *env, jclass klass, const char *name, const char *sig, int isStatic);
+static jclass checkFindClass(JNIEnv *env, const char *name);
+static int process_vmargs(int argc, char *argv[], char *vmargv[], char *uargv[]);
+static char **update_environ_with_java_home(void);
+static void print_environ(char **env);
+static char *get_classpath(char *r_home);
 
-CTXT R_getParentFunctionContext(CTXT c) {
-	return ((call_R_getParentFunctionContext) callbacks[R_getParentFunctionContext_x])(c);
-}
 
-SEXP R_getContextEnv(CTXT c) {
-	return ((call_R_getContextEnv) callbacks[R_getContextEnv_x])(c);
-}
+// ----------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------
+// The embedding API
+// So far it seems that GNU R can be embedded by invoking either:
+//      1) Rf_initEmbeddedR: initializing the main loop without actually running it after which the user
+//          can e.g. eval code using Rf_eval, finish with Rf_endEmbeddedR
+//      2) Rf_initialize_R & Rf_mainloop: initializing and runnning the main loop
 
-SEXP R_getContextFun(CTXT c) {
-	return ((call_R_getContextFun) callbacks[R_getContextFun_x])(c);
-}
+// Does the heavy work of starting up the JVM and invoking REmbedded#initializeR, which should be the
+// only upcall to Java made via JNI. If setupRmainloop != 0, then also initialized the main loop (does not run it).
+static int initializeFastR(int argc, char *argv[], int setupRmainloop);
 
-SEXP R_getContextCall(CTXT c) {
-	return ((call_R_getContextCall) callbacks[R_getContextCall_x])(c);
+// initializes R, but user is expected (TODO: probably) to invoke the main loop after that
+int Rf_initialize_R(int argc, char *argv[]) {
+	return initializeFastR(argc, argv, 0);
 }
 
-SEXP R_getContextSrcRef(CTXT c) {
-    return ((call_R_getContextSrcRef) callbacks[R_getContextSrcRef_x])(c);
+// initializes R and the main loop without running it
+int Rf_initEmbeddedR(int argc, char *argv[]) {
+	return initializeFastR(argc, argv, 1);
 }
 
-int R_insideBrowser() {
-    return ((call_R_insideBrowser) callbacks[R_insideBrowser_x])();
+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->NoRenviron = FALSE;
 }
 
-int R_isGlobal(CTXT c) {
-    return ((call_R_isGlobal) callbacks[R_isGlobal_x])(c);
+// Allows to set-up some params before the main loop is initialized
+// This call has to be made via JNI as we are not in a down-call, i.e. in truffle context, when this gets executed.
+void R_SetParams(Rstart rs) {
+	JNIEnv *jniEnv = getEnv();
+	jmethodID setParamsMethodID = checkGetMethodID(jniEnv, rembeddedClass, "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);
 }
 
-int R_isEqual(void* x, void* y) {
-	return ((call_R_isEqual) callbacks[R_isEqual_x])(x, y);
+// Runs the main REPL loop
+void Rf_mainloop(void) {
+	JNIEnv *jniEnv = getEnv();
+	setupOverrides();
+	jmethodID mainloopMethod = checkGetMethodID(jniEnv, rembeddedClass, "runRmainloop", "()V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, rembeddedClass, mainloopMethod);
 }
 
+void R_Suicide(const char *s) { ptr_R_Suicide(s); }
 
-// 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;
+void Rf_endEmbeddedR(int fatal) {
+    // TODO: invoke com.oracle.truffle.r.engine.shell.REmbedded#endRmainloop
+	(*javaVM)->DestroyJavaVM(javaVM);
+	//TODO fatal
 }
 
-// Forward declarations of helper functions
-static char **update_environ_with_java_home(void);
-static void print_environ(char **env);
-static char *get_classpath(char *r_home);
-
-int Rf_initialize_R(int argc, char *argv[]) {
+static int initializeFastR(int argc, char *argv[], int setupRmainloop) {
 	if (initialized) {
 		fprintf(stderr, "%s", "R is already initialized\n");
 		exit(1);
@@ -242,104 +216,107 @@ int Rf_initialize_R(int argc, char *argv[]) {
 	rInterfaceCallbacksClass = checkFindClass(jniEnv, "com/oracle/truffle/r/runtime/RInterfaceCallbacks");
 	rembeddedClass = checkFindClass(jniEnv, "com/oracle/truffle/r/engine/shell/REmbedded");
 	jclass stringClass = checkFindClass(jniEnv, "java/lang/String");
-	jmethodID initializeMethod = checkGetMethodID(jniEnv, rembeddedClass, "initializeR", "([Ljava/lang/String;)V", 1);
+	jmethodID initializeMethod = checkGetMethodID(jniEnv, rembeddedClass, "initializeR", "([Ljava/lang/String;Z)V", 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);
 	}
+	if (setupRmainloop) {
+        setupOverrides();
+	}
 	// Can't TRACE this upcall as system not initialized
-	(*jniEnv)->CallStaticObjectMethod(jniEnv, rembeddedClass, initializeMethod, argsArray);
+	(*jniEnv)->CallStaticObjectMethod(jniEnv, rembeddedClass, initializeMethod, argsArray, setupRmainloop);
 	initialized++;
 	return 0;
 }
 
+// -----------------------------------------------------------------------------------------------
+// -----------------------------------------------------------------------------------------------
+// UpCalls from native to Java (IDE and tools up-calls)
+
 char *R_HomeDir(void) {
-    // TODO: find out if this function could be invoked before the JVM and FastR get initialized
-    // in which case the access to callbacks will cause SIGSEGV
+    // TODO: why here? is it not implemented by RFFI already?
     return ((call_R_HomeDir) callbacks[R_HomeDir_x])();
 }
 
-void R_SaveGlobalEnvToFile(const char *f) {
-	unimplemented("R_SaveGlobalEnvToFile");
+CTXT R_getGlobalFunctionContext() {
+    return ((call_R_getGlobalFunctionContext) callbacks[R_getGlobalFunctionContext_x])();
 }
 
-void R_Suicide(const char *s) { ptr_R_Suicide(s); }
+CTXT R_getParentFunctionContext(CTXT c) {
+	return ((call_R_getParentFunctionContext) callbacks[R_getParentFunctionContext_x])(c);
+}
 
-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);
+SEXP R_getContextEnv(CTXT c) {
+	return ((call_R_getContextEnv) callbacks[R_getContextEnv_x])(c);
 }
 
-// This call has to be made via JNI as we are not in a down-call, i.e. in truffle context, when this gets executed.
-void R_SetParams(Rstart rs) {
-	JNIEnv *jniEnv = getEnv();
-	jmethodID setParamsMethodID = checkGetMethodID(jniEnv, rembeddedClass, "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);
+SEXP R_getContextFun(CTXT c) {
+	return ((call_R_getContextFun) callbacks[R_getContextFun_x])(c);
 }
 
-void R_SizeFromEnv(Rstart rs) {
-	unimplemented("R_SizeFromEnv");
+SEXP R_getContextCall(CTXT c) {
+	return ((call_R_getContextCall) callbacks[R_getContextCall_x])(c);
 }
 
-void R_common_command_line(int *a, char **b, Rstart rs) {
-	unimplemented("R_common_command_line");
+SEXP R_getContextSrcRef(CTXT c) {
+    return ((call_R_getContextSrcRef) callbacks[R_getContextSrcRef_x])(c);
 }
 
-void R_set_command_line_arguments(int argc, char **argv) {
-	unimplemented("R_set_command_line_arguments");
+int R_insideBrowser() {
+    return ((call_R_insideBrowser) callbacks[R_insideBrowser_x])();
 }
 
+int R_isGlobal(CTXT c) {
+    return ((call_R_isGlobal) callbacks[R_isGlobal_x])(c);
+}
 
-int Rf_initEmbeddedR(int argc, char *argv[]) {
-	Rf_initialize_R(argc, argv);
-//	R_Interactive = TRUE;
-    setup_Rmainloop();
-    return 1;
+int R_isEqual(void* x, void* y) {
+	return ((call_R_isEqual) callbacks[R_isEqual_x])(x, y);
 }
 
-void Rf_endEmbeddedR(int fatal) {
-	(*javaVM)->DestroyJavaVM(javaVM);
-	//TODO fatal
+// -----------------------------------------------------------------------------------------------
+// -----------------------------------------------------------------------------------------------
+// Downcalls from Java. We invoke these functions via REmbedRFFI
+
+static void writeConsoleImpl(char *cbuf, int len, int otype) {
+    if (ptr_R_WriteConsole == NULL) {
+        // otype gives std (0) or err (1)
+        (*ptr_R_WriteConsoleEx)(cbuf, len, otype);
+    } else {
+        (*ptr_R_WriteConsole)(cbuf, len);
+    }
 }
 
-static void setupOverrides(void);
+void rembedded_cleanup(int x, int y, int z) {
+    ptr_R_CleanUp(x, y, z);
+}
 
-void Rf_mainloop(void) {
-	JNIEnv *jniEnv = getEnv();
-	setupOverrides();
-	jmethodID mainloopMethod = checkGetMethodID(jniEnv, rembeddedClass, "runRmainloop", "()V", 1);
-	(*jniEnv)->CallStaticVoidMethod(jniEnv, rembeddedClass, mainloopMethod);
+void rembedded_suicide(char* msg) {
+    ptr_R_Suicide(msg);
 }
 
-// functions that can be assigned by an embedded client to change behavior
+void rembedded_write_console(char *cbuf, int len) {
+    writeConsoleImpl(cbuf, len, 0);
+}
 
-// Note: pointer to this function is typically saved by the user to be called from that
-// user's R_Suicide override to actually really commit the suicide. We invoke this through
-// JNI intentionally to avoid any potential problems with NFI being called while destroying the VM.
-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 rembedded_write_err_console(char *cbuf, int len) {
+    writeConsoleImpl(cbuf, len, 1);
+}
+
+char* rembedded_read_console(const char* prompt) {
+    unsigned char* cbuf = malloc(sizeof(char) * 1024);
+    int n = (*ptr_R_ReadConsole)(prompt, cbuf, 1024, 0);
+    return cbuf;
+}
+
+// -----------------------------------------------------------------------------------------------
+// -----------------------------------------------------------------------------------------------
+// Unimplemented API functions (to make the linker happy and as a TODO list)
+
+void R_SaveGlobalEnvToFile(const char *f) {
+	unimplemented("R_SaveGlobalEnvToFile");
 }
 
 void uR_ShowMessage(const char *x) {
@@ -347,7 +324,8 @@ void uR_ShowMessage(const char *x) {
 }
 
 int uR_ReadConsole(const char *a, unsigned char *b, int c, int d) {
-	return (int) unimplemented("R_ReadConsole");
+	unimplemented("R_ReadConsole");
+	return 0;
 }
 
 void uR_WriteConsole(const char *x, int y) {
@@ -374,17 +352,32 @@ void uR_Busy(int x) {
 	unimplemented("R_Busy");
 }
 
+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 uR_ShowFiles(int a, const char **b, const char **c,
 	       const char *d, Rboolean e, const char *f) {
-	return (int) unimplemented("R_ShowFiles");
+	unimplemented("R_ShowFiles");
+	return 0;
 }
 
 int uR_ChooseFile(int a, char *b, int c) {
-	return (int) unimplemented("R_ChooseFile");
+	unimplemented("R_ChooseFile");
+	return 0;
 }
 
 int uR_EditFile(const char *a) {
-	return (int) unimplemented("R_EditFile");
+	unimplemented("R_EditFile");
+	return 0;
 }
 
 void uR_loadhistory(SEXP a, SEXP b, SEXP c, SEXP d) {
@@ -399,8 +392,9 @@ 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("");
+int uR_EditFiles(int a, const char **b, const char **c, const char *d) {
+	unimplemented("uR_EditFiles");
+	return 0;
 }
 
 SEXP udo_selectlist(SEXP a, SEXP b, SEXP c, SEXP d) {
@@ -419,6 +413,49 @@ void uR_ProcessEvents(void) {
 	unimplemented("R_ProcessEvents");
 }
 
+void uR_PolledEvents(void) {
+	unimplemented("R_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) {
+	unimplemented("R_checkActivity");
+	return NULL;
+}
+
+void R_runHandlers(InputHandler *handlers, fd_set *mask) {
+	unimplemented("R_runHandlers");
+}
+
+// -----------------------------------------------------------------------------------------------
+// -----------------------------------------------------------------------------------------------
+// Functions that can be assigned by an embedded client to change behavior.
+// On the Java side the RInterfaceCallbacks remembers for each callback whether its default
+// value (pointer to the default implementation) was changed for some user defined function
+// and in such case Java down-calls to that function if the event occures. Moreover the default
+// values of those pointers (and functions they point to) should be also functional (not all are yet),
+// because the user code sometimes saves the original value before overriding it to invoke it in the
+// user's overridden version. 'setupOverrides' updates the Java side enum via JNI and is invoked from
+// public functions that initialize the R embedding at the point where those pointers should be
+// already overridden by the user. (We may reconsider that and always down-call if some embedding
+// applications override those pointers after initialization).
+
+
+// Note: pointer to this function is typically saved by the user to be called from that
+// user's R_Suicide override to actually really commit the suicide. We invoke this through
+// JNI intentionally to avoid any potential problems with NFI being called while destroying the VM.
+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_CleanUp(SA_TYPE x, int y, int z) {
     ((call_R_CleanUp) callbacks[R_CleanUp_x])(x, y, z);
 }
@@ -447,9 +484,9 @@ 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 (* R_PolledEvents)(void) = uR_PolledEvents;
 
-// This call cannot be made via NFI because it is invoked from Rf_mainloop,
-// which is exported C function expected to be invoked by the embedded before actually starting R engine.
+// This call cannot be made via callbacks array because it may be invoked before FastR is fully initialized.
 void setupOverrides(void) {
 	JNIEnv *jniEnv = getEnv();
 	jmethodID ovrMethodID = checkGetMethodID(jniEnv, rInterfaceCallbacksClass, "override", "(Ljava/lang/String;)V", 1);
@@ -472,74 +509,74 @@ void setupOverrides(void) {
 	}
 }
 
-static void writeConsoleImpl(char *cbuf, int len, int otype) {
-    if (ptr_R_WriteConsole == NULL) {
-        // otype gives std (0) or err (1)
-        (*ptr_R_WriteConsoleEx)(cbuf, len, otype);
-    } else {
-        (*ptr_R_WriteConsole)(cbuf, len);
-    }
-}
-
-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");
-}
-
 // -----------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------
-// Downcalls from Java. We invoke these functions via REmbedRFFI
+// Helpers
 
-void rembedded_cleanup(int x, int y, int z) {
-    ptr_R_CleanUp(x, y, z);
+// 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;
 }
 
-void rembedded_suicide(char* msg) {
-    ptr_R_Suicide(msg);
-}
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
 
-void rembedded_write_console(char *cbuf, int len) {
-    writeConsoleImpl(cbuf, len, 0);
+static void perror_exit(char *msg) {
+	perror(msg);
+	exit(1);
 }
 
-void rembedded_write_err_console(char *cbuf, int len) {
-    writeConsoleImpl(cbuf, len, 1);
+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;
 }
 
-char* rembedded_read_console(const char* prompt) {
-    unsigned char* cbuf = malloc(sizeof(char) * 1024);
-    int n = (*ptr_R_ReadConsole)(prompt, cbuf, 1024, 0);
-    return cbuf;
+static JNIEnv* getEnv() {
+    return jniEnv;
 }
 
-// -----------------------------------------------------------------------------------------------
-// -----------------------------------------------------------------------------------------------
-// Helpers
-
-
-int R_wait_usec;    // TODO: necessary to resolve externals? otherwise dead code
-
-#include <unistd.h>
-#include <errno.h>
+static jmethodID checkGetMethodID(JNIEnv *env, jclass klass, const char *name, const char *sig, int isStatic) {
+    jmethodID methodID = isStatic ? (*env)->GetStaticMethodID(env, klass, name, sig) : (*env)->GetMethodID(env, klass, name, sig);
+    if (methodID == NULL) {
+        char buf[1024];
+        strcpy(buf, "failed to find ");
+        strcat(buf, isStatic ? "static" : "instance");
+        strcat(buf, " method ");
+        strcat(buf, name);
+        strcat(buf, "(");
+        strcat(buf, sig);
+        strcat(buf, ")");
+        (*env)->FatalError(env, buf);
+    }
+    return methodID;
+}
 
-static void perror_exit(char *msg) {
-	perror(msg);
-	exit(1);
+static jclass checkFindClass(JNIEnv *env, const char *name) {
+    jclass klass = (*env)->FindClass(env, name);
+    if (klass == NULL) {
+        char buf[1024];
+        strcpy(buf, "failed to find class ");
+        strcat(buf, name);
+        strcat(buf, ".\nDid you set R_HOME to the correct location?");
+        (*env)->FatalError(env, buf);
+    }
+    return (*env)->NewGlobalRef(env, klass);
 }
 
 // support for getting the correct classpath for the VM
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
index 848300a58a428dff3e1b9f4e25df014844e6d13a..bc6bf9f3a9bbcbccdcbf17657e064bcfd6713c4b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RObject;
 
@@ -101,6 +102,17 @@ public abstract class RFFIContext extends RFFI {
     public void initializeVariables(RContext context) {
     }
 
+    /**
+     * Invoked as part of the R embedded initialization just before returning back to the C user
+     * code. Should do any set-up necessary for the RFFI to be fully functional even outside the
+     * context of a down-call. At the moment the assumption is that embedded code is always single
+     * threaded and always creates exactly one context. This method shall be invoked after
+     * {@link #initialize(RContext)} and {@link #initializeVariables(RContext)}.
+     */
+    public void initializeEmbedded(RContext context) {
+        throw RInternalError.unimplemented("R Embedding not supported with " + this.getClass().getSimpleName() + " RFFI backend.");
+    }
+
     public long beforeDowncall() {
         callDepth++;
         return 0;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArray.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArray.java
index cf414ccbd0164fea7831a2bd7e7c38b8feb1f3e6..e35b820fb1aa50de4d89c780e7359e2cc5c8b264 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArray.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArray.java
@@ -58,6 +58,7 @@ public final class NativeCharArray extends NativeUInt8Array {
     /**
      * Finds the null terminator and creates the Java String accordingly.
      */
+    @TruffleBoundary
     public String getStringFromOutputBuffer() {
         assert !fakesNullTermination() : "create the buffer string via createOutputBuffer()";
         byte[] mbuf = getValue();