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 b86229a115ec850ed2d81b4533c2efdd51a16cb7..d6e16e35f3ab64c5b53d685795487bde09fe74b5 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
@@ -13,6 +13,7 @@
 #include <Rdynload.h>
 
 // Registering routines from loaded shared libraries
+// Currently an exception to the rule that all upcalls go via CallRFFIHelper
 
 static jclass DLLClass;
 static jclass JNI_PkgInitClass;
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 ff81c0002ad83c7a456d22843abb2b4c022290bd..3972ae97f451a894d5e79a20b95c3e47276496b6 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -30,6 +30,8 @@
 // to ensure that a global JNI handle is created (if necessary) and returned,
 // otherwise a GC might reclaim the result.
 
+// N.B. ALL functions go via CallRFFIHelper to provide a single point of re-entry
+
 static jmethodID Rf_ScalarIntegerMethodID;
 static jmethodID Rf_ScalarDoubleMethodID;
 static jmethodID Rf_ScalarStringMethodID;
@@ -50,10 +52,11 @@ static jmethodID Rf_getAttribMethodID;
 static jmethodID Rf_setAttribMethodID;
 static jmethodID Rf_isStringMethodID;
 static jmethodID Rf_isNullMethodID;
+static jmethodID Rf_installMethodID;
 static jmethodID Rf_warningcallMethodID;
 static jmethodID Rf_warningMethodID;
 static jmethodID Rf_errorMethodID;
-static jmethodID Rf_NewHashedEnvMethodID;
+static jmethodID R_NewHashedEnvMethodID;
 static jmethodID Rf_classgetsMethodID;
 static jmethodID Rf_rPsortMethodID;
 static jmethodID Rf_iPsortMethodID;
@@ -110,22 +113,16 @@ 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 SymbolHandleClass;
-static jmethodID symbolHandleConsMethodID;
-
-static jclass RExternalPtrClass;
-static jmethodID createExternalPtrMethodID;
-static jmethodID externalPtrGetAddrMethodID;
-static jmethodID externalPtrGetTagMethodID;
-static jmethodID externalPtrGetProtMethodID;
-static jmethodID externalPtrSetAddrMethodID;
-static jmethodID externalPtrSetTagMethodID;
-static jmethodID externalPtrSetProtMethodID;
+static jmethodID R_MakeExternalPtrMethodID;
+static jmethodID R_ExternalPtrAddrMethodID;
+static jmethodID R_ExternalPtrTagMethodID;
+static jmethodID R_ExternalPtrProtMethodID;
+static jmethodID R_SetExternalPtrAddrMethodID;
+static jmethodID R_SetExternalPtrTagMethodID;
+static jmethodID R_SetExternalPtrProtMethodID;
 
 static jmethodID R_computeIdenticalMethodID;
 static jmethodID Rf_copyListMatrixMethodID;
@@ -154,6 +151,7 @@ void init_internals(JNIEnv *env) {
 	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);
 	Rf_isNullMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_isNull", "(Ljava/lang/Object;)I", 1);
+	Rf_installMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_install", "(Ljava/lang/String;)Ljava/lang/Object;", 1);
 	Rf_warningMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_warning", "(Ljava/lang/String;)V", 1);
 	Rf_warningcallMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_warningcall", "(Ljava/lang/Object;Ljava/lang/String;)V", 1);
 	Rf_errorMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_error", "(Ljava/lang/String;)V", 1);
@@ -162,7 +160,7 @@ void init_internals(JNIEnv *env) {
 	Rf_allocateArrayMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_allocateArray", "(ILjava/lang/Object;)Ljava/lang/Object;", 1);
 	Rf_duplicateMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_duplicate", "(Ljava/lang/Object;I)Ljava/lang/Object;", 1);
 	Rf_anyDuplicatedMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_anyDuplicated", "(Ljava/lang/Object;I)I", 1);
-	Rf_NewHashedEnvMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_createNewEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;Ljava/lang/String;ZI)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 1);
+	R_NewHashedEnvMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;Ljava/lang/String;ZI)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 1);
 	Rf_classgetsMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_classgets", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
 	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);
@@ -218,22 +216,17 @@ void init_internals(JNIEnv *env) {
 	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", "(Lcom/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle;Ljava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 1);
-	externalPtrGetAddrMethodID = checkGetMethodID(env, RExternalPtrClass, "getAddr", "()Lcom/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle;", 0);
-	externalPtrGetTagMethodID = checkGetMethodID(env, RExternalPtrClass, "getTag", "()Ljava/lang/Object;", 0);
-	externalPtrGetProtMethodID = checkGetMethodID(env, RExternalPtrClass, "getProt", "()Ljava/lang/Object;", 0);
-	externalPtrSetAddrMethodID = checkGetMethodID(env, RExternalPtrClass, "setAddr", "(Lcom/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle;)V", 0);
-	externalPtrSetTagMethodID = checkGetMethodID(env, RExternalPtrClass, "setTag", "(Ljava/lang/Object;)V", 0);
-	externalPtrSetProtMethodID = checkGetMethodID(env, RExternalPtrClass, "setProt", "(Ljava/lang/Object;)V", 0);
-
-	SymbolHandleClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle");
-	symbolHandleConsMethodID = checkGetMethodID(env, SymbolHandleClass, "<init>", "(Ljava/lang/Object;)V", 0);
+	resetAndGetHandlerStacksMethodID = checkGetMethodID(env, CallRFFIHelperClass, "resetAndGetErrorHandlerStacks", "()Ljava/lang/Object;", 1);
+	restoreHandlerStacksMethodID = checkGetMethodID(env, CallRFFIHelperClass, "restoreErrorHandlerStacks", "(Ljava/lang/Object;)V", 1);
+
+	R_MakeExternalPtrMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_MakeExternalPtr", "(JLjava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 1);
+	R_ExternalPtrAddrMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ExternalPtrAddr", "(Ljava/lang/Object;)J", 1);
+	R_ExternalPtrTagMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ExternalPtrTag", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	R_ExternalPtrProtMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ExternalPtrProt", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
+	R_SetExternalPtrAddrMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_SetExternalPtrAddr", "(Ljava/lang/Object;J)V", 1);
+	R_SetExternalPtrTagMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_SetExternalPtrTag", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
+	R_SetExternalPtrProtMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_SetExternalPtrProt", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
+
 	CharSXPWrapperClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper$CharSXPWrapper");
 	CharSXPWrapperContentsFieldID = checkGetFieldID(env, CharSXPWrapperClass, "contents", "Ljava/lang/String;", 0);
 
@@ -484,7 +477,7 @@ 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);
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_installMethodID, string);
 	return checkRef(thisenv, result);
 }
 
@@ -492,7 +485,7 @@ SEXP Rf_installChar(SEXP charsxp) {
 	TRACE(TARGp, charsxp);
 	JNIEnv *thisenv = getEnv();
 	jstring string = stringFromCharSXP(thisenv, charsxp);
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, createSymbolMethodID, string);
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_installMethodID, string);
 	return checkRef(thisenv, result);
 }
 
@@ -533,7 +526,7 @@ 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);
+	(*thisenv)->SetByteArrayRegion(thisenv, bytes, 0, len, (const jbyte *) x);
 	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_mkCharLenCEMethodID, bytes, (int) enc);
 	return checkRef(thisenv, result);
 }
@@ -550,13 +543,13 @@ SEXP Rf_mkString(const char *s) {
 int Rf_ncols(SEXP x) {
 	TRACE(TARGs, x);
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ncolsMethodID, x);
+	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_ncolsMethodID, x);
 }
 
 int Rf_nrows(SEXP x) {
 	TRACE(TARGs, x);
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_nrowsMethodID, x);
+	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_nrowsMethodID, x);
 }
 
 
@@ -686,17 +679,15 @@ void R_ProcessEvents(void) {
 }
 
 // Tools package support, not in public API
-
 SEXP R_NewHashedEnv(SEXP parent, SEXP size) {
 	JNIEnv *thisenv = getEnv();
-	int sizeAsInt = Rf_asInteger(size);
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, Rf_NewHashedEnvMethodID, parent, NULL, JNI_TRUE, sizeAsInt);
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_NewHashedEnvMethodID, parent, size);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_classgets(SEXP vec, SEXP klass) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, Rf_classgetsMethodID, vec, klass);
+	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_classgetsMethodID, vec, klass);
 	return checkRef(thisenv, result);
 }
 
@@ -1342,7 +1333,7 @@ const char *R_CHAR(SEXP charsxp) {
 	TRACE("%s(%p)", charsxp);
 	JNIEnv *thisenv = getEnv();
 	jstring string = stringFromCharSXP(thisenv, charsxp);
-	char *copyChars = stringToChars(thisenv, string);
+	char *copyChars = (char *) stringToChars(thisenv, string);
 	TRACE(" %s(%s)\n", copyChars);
 	return copyChars;
 }
@@ -1516,41 +1507,40 @@ SEXP R_forceAndCall(SEXP e, int n, SEXP rho) {
 
 SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot) {
 	JNIEnv *thisenv = getEnv();
-	jobject handle = (*thisenv)->CallStaticObjectMethod(thisenv, SymbolHandleClass, symbolHandleConsMethodID, (jobject) p);
-	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, createExternalPtrMethodID, handle, tag, prot);
+	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_MakeExternalPtrMethodID, (jlong) p, tag, prot);
     return checkRef(thisenv, result);
 }
 
 void *R_ExternalPtrAddr(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	return (void *) (*thisenv)->CallLongMethod(thisenv, s, externalPtrGetAddrMethodID);
+	return (void *) (*thisenv)->CallStaticLongMethod(thisenv, CallRFFIHelperClass, R_ExternalPtrAddrMethodID, s);
 }
 
 SEXP R_ExternalPtrTag(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result =  (*thisenv)->CallObjectMethod(thisenv, s, externalPtrGetTagMethodID);
+	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_ExternalPtrTagMethodID, s);
     return checkRef(thisenv, result);
 }
 
 SEXP R_ExternalPtrProt(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result =  (*thisenv)->CallObjectMethod(thisenv, s, externalPtrGetProtMethodID);
+	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_ExternalPtrProtMethodID, s);
     return checkRef(thisenv, result);
 }
 
 void R_SetExternalPtrAddr(SEXP s, void *p) {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallLongMethod(thisenv, s, externalPtrSetAddrMethodID, (jlong) p);
+	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, R_SetExternalPtrAddrMethodID, s, (jlong) p);
 }
 
 void R_SetExternalPtrTag(SEXP s, SEXP tag) {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallObjectMethod(thisenv, s, externalPtrSetTagMethodID, tag);
+	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, R_SetExternalPtrTagMethodID, s, tag);
 }
 
 void R_SetExternalPtrProtected(SEXP s, SEXP p) {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallObjectMethod(thisenv, s, externalPtrSetProtMethodID, p);
+	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, R_SetExternalPtrProtMethodID, s, p);
 }
 
 void R_ClearExternalPtr(SEXP s) {
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 aa7a7506b4e8ff58c4fde9ed424c98c9ff848c64..0010587bccde3b3ea603407a66e2a05727d9f2f9 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
@@ -33,13 +33,8 @@
  * (portably) for MT use. JNI provides no help.
  */
 jclass CallRFFIHelperClass;
-jclass RDataFactoryClass;
-jclass RRuntimeClass;
 jclass CharSXPWrapperClass;
 
-static jclass RInternalErrorClass;
-static jmethodID unimplementedMethodID;
-jmethodID createSymbolMethodID;
 static jmethodID validateMethodID;
 
 static JNIEnv *curenv = NULL;
@@ -114,12 +109,7 @@ void init_utils(JNIEnv *env) {
 		    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/jni/CallRFFIHelper");
-	RRuntimeClass = checkFindClass(env, "com/oracle/truffle/r/runtime/RRuntime");
-	RInternalErrorClass = checkFindClass(env, "com/oracle/truffle/r/runtime/RInternalError");
-	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);
     cachedGlobalRefs = calloc(CACHED_GLOBALREFS_INITIAL_SIZE, sizeof(GlobalRefElem));
     cachedGlobalRefsLength = CACHED_GLOBALREFS_INITIAL_SIZE;
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 9ace813ba473f3d71d4f44b9972c9aea3fc26eda..3a3539579ec0912b64229bbe5709c4c1cab4c719 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
@@ -38,7 +38,6 @@ void setEnv(JNIEnv *env);
 jclass checkFindClass(JNIEnv *env, const char *name);
 jmethodID checkGetMethodID(JNIEnv *env, jclass klass, const char *name, const char *sig, int isStatic);
 jfieldID checkGetFieldID(JNIEnv *env, jclass klass, const char *name, const char *sig, int isStatic);
-extern jmethodID createSymbolMethodID;
 
 // use for an unimplemented API function
 void *unimplemented(char *msg);
@@ -91,9 +90,7 @@ void setEmbedded(void);
 
 void setTempDir(JNIEnv *, jstring tempDir);
 
-extern jclass RDataFactoryClass;
 extern jclass CallRFFIHelperClass;
-extern jclass RRuntimeClass;
 extern FILE *traceFile;
 
 // tracing/debugging support, set to 1 and recompile to enable
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper.java
index 5849eeabcc7cd2fcd6e7d881864ba24a800d6020..fa73127bcec10decf22135b9317a62cbf70d5ce1 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper.java
@@ -78,6 +78,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.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
@@ -99,6 +100,14 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
  */
 public class CallRFFIHelper {
 
+    /**
+     * Internally GNU R distinguishes "strings" and "vectors of strings" using the {@code CHARSXP}
+     * and {@code STRSXP} types, respectively. Although this difference is invisible at the R level,
+     * it manifests itself in the R FFI as several functions traffic in the {@code CHARSXP} type.
+     * Since FastR already uses {@code String} to denote a length-1 string vector, it cannot be used
+     * to represent a {@code CHARSXP}, so this class exists to do so.
+     *
+     */
     public static final class CharSXPWrapper {
         private final String contents;
 
@@ -420,6 +429,13 @@ public class CallRFFIHelper {
         return result;
     }
 
+    public static Object Rf_install(String name) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_install", name);
+        }
+        return RDataFactory.createSymbolInterned(name);
+    }
+
     public static Object Rf_lengthgets(Object x, int newSize) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
@@ -1018,15 +1034,6 @@ public class CallRFFIHelper {
         // TODO: copy OBJECT? and S4 attributes
     }
 
-    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);
@@ -1071,6 +1078,27 @@ public class CallRFFIHelper {
         }
     }
 
+    /**
+     * Helper function for {@code R_TopLevelExec} which is similar to {@code R_TryEval} except that
+     * a C function is invoked (in the native layer) instead of an R expression. assert: this is
+     * ONLY called from R_TopLevelExec prior to calling C function.
+     */
+    public static Object resetAndGetErrorHandlerStacks() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_TopLevelExec");
+        }
+        return RErrorHandling.resetAndGetHandlerStacks();
+    }
+
+    /**
+     * Helper function for {@code R_TopLevelExec}, see {@link #resetAndGetErrorHandlerStacks()},
+     * called after C function returns.
+     */
+    public static void restoreErrorHandlerStacks(Object stacks) {
+        RErrorHandling.HandlerStacks handlerStacks = guaranteeInstanceOf(stacks, RErrorHandling.HandlerStacks.class);
+        RErrorHandling.restoreHandlerStacks(handlerStacks);
+    }
+
     public static int RDEBUG(Object x) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("RDEBUG", x);
@@ -1436,4 +1464,68 @@ public class CallRFFIHelper {
         return RNull.instance;
     }
 
+    public static RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_MakeExternalPtr", addr, tag, prot);
+        }
+        return RDataFactory.createExternalPtr(new SymbolHandle(addr), tag, prot);
+    }
+
+    public static long R_ExternalPtrAddr(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrAddr", x);
+        }
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        return p.getAddr().asAddress();
+    }
+
+    public static Object R_ExternalPtrTag(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrTag", x);
+        }
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        return p.getTag();
+    }
+
+    public static Object R_ExternalPtrProt(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+        }
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        return p.getProt();
+    }
+
+    public static void R_SetExternalPtrAddr(Object x, long addr) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_SetExternalPtrAddr", x);
+        }
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        p.setAddr(new SymbolHandle(addr));
+    }
+
+    public static void R_SetExternalPtrTag(Object x, Object tag) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_SetExternalPtrTag", x);
+        }
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        p.setTag(tag);
+    }
+
+    public static void R_SetExternalPtrProt(Object x, Object prot) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+        }
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        p.setProt(prot);
+    }
+
+    public static REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, name, hashed, initialSize);
+        }
+        REnvironment env = RDataFactory.createNewEnv(name, hashed, initialSize);
+        RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
+        return env;
+    }
+
 }
diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py
index 8b88672dec8e4eabbae35236a26d532e6f0a01c5..6815ab54d6de730e1afd12291a18fd8c4ddde57f 100644
--- a/mx.fastr/mx_fastr.py
+++ b/mx.fastr/mx_fastr.py
@@ -533,6 +533,26 @@ def gnu_rscript(args, env=None):
     cmd = [join(_gnur_path(), 'Rscript')] + args
     return mx.run(cmd, nonZeroIsFatal=False, env=env)
 
+def nativebuild(args):
+    '''
+    force the build of part or all of the native project
+    '''
+    parser = ArgumentParser(prog='nativebuild')
+    parser.add_argument('--all', action='store_true', help='clean and build everything, else just ffi')
+    args = parser.parse_args(args)
+    nativedir = mx.project('com.oracle.truffle.r.native').dir
+    if args.all:
+        return subprocess.call(['make clean && make'], shell=True, cwd=nativedir)
+    else:
+        ffidir = join(nativedir, 'fficall')
+        jni_done = join(ffidir, 'jni.done')
+        jniboot_done = join(ffidir, 'jniboot.done')
+        if os.path.exists(jni_done):
+            os.remove(jni_done)
+        if os.path.exists(jniboot_done):
+            os.remove(jniboot_done)
+        return mx.build(['--no-java'])
+
 def mx_post_parse_cmd_line(opts):
     mx_fastr_dists.mx_post_parse_cmd_line(opts)
 
@@ -563,6 +583,7 @@ _commands = {
     'rupdatelib' : [mx_copylib.updatelib, '[]'],
     'gnu-r' : [gnu_r, '[]'],
     'gnu-rscript' : [gnu_rscript, '[]'],
+    'nativebuild' : [nativebuild, '[]'],
     }
 
 mx.update_commands(_fastr_suite, _commands)