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..a207d8247fa409dd2d6c4777f3473b288171f417 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,13 @@ 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.getInstance().completeEmbeddedInitialization();
+            // TODO: push callbacks
+            // stay in the context TODO should we?
+        }
     }
 
     /**
@@ -110,12 +117,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);
     }
 
     /**
@@ -135,8 +140,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.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