diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java
index b2c2a28a826ed7994a44f37c6aac5c3514170fe2..1b8aca885df504ab57b6b46bcac74eec7523a8b6 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java
@@ -22,11 +22,8 @@
  */
 package com.oracle.truffle.r.engine.interop;
 
-import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.MessageResolution;
@@ -36,23 +33,13 @@ import com.oracle.truffle.r.engine.TruffleRLanguage;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RForeignAccessFactory;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDouble;
-import com.oracle.truffle.r.runtime.data.RDoubleSequence;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RIntSequence;
-import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
-import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 import com.oracle.truffle.r.runtime.data.RUnboundValue;
@@ -60,8 +47,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
 import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
-import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
 
 /**
  * A {@link ForeignAccess} instance captures the {@link Thread} that creates it and all uses are
@@ -73,16 +58,6 @@ import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
  * This factory provides a generic solution for all FastR types (all of which are
  * {@link TruffleObject}s), at some cost in performance.
  *
- * The REALLY bad news is that we cannot use {@link RContext} to store the state because, although
- * that should be possible, at the time the call to {@link #getForeignAccess(RTruffleObject)}
- * happens the {@link RContext} may not have been associated with a thread, so
- * {@link RContext#getInstance()} will fail. In short the mapping has to be established using
- * {@link Thread} not {@link RContext} and there is no call that informs us ahead of a call to
- * {@link #getForeignAccess} that a new thread is in play. We use a Truffle {@link Assumption} to
- * provide a fast path in the normal, single-threaded, case. TODO Apparently a call to
- * {@link #getForeignAccess(RTruffleObject)} should,in fact, only occur on the slow path, and an
- * assertion to that effect has been added. If true, then the fast path code can be simplified.
- *
  * For most types we use the {@link MessageResolution} facility to automatically generate the
  * factory for creating the {@link ForeignAccess} instance. The exceptions are the (many) subclasses
  * of {@link RAbstractVector} as these have the same handling but the generator cannot handle
@@ -90,198 +65,90 @@ import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
  *
  */
 public final class RForeignAccessFactoryImpl implements RForeignAccessFactory {
-    /**
-     * The subset of the full set of types that are supported for foreign access. N.B. This list
-     * includes types that are not expected to travel between high-level languages, but may travel
-     * into the native world (when implemented in Truffle).
-     */
-    private static final Class<?>[] FOREIGN_CLASSES = new Class<?>[]{
-                    RRaw.class, RComplex.class, RIntSequence.class,
-                    RDoubleSequence.class, RIntVector.class, RDoubleVector.class,
-                    RRawVector.class, RComplexVector.class, RStringVector.class, RLogicalVector.class,
-                    RFunction.class, RNull.class, REnvironment.class,
-                    RList.class, RSymbol.class,
-                    RPairList.class, RExternalPtr.class, RUnboundValue.class,
-                    DLLInfo.class, DotSymbol.class,
-                    NativeRawArray.class, NativeCharArray.class, NativeIntegerArray.class,
-                    NativeDoubleArray.class, NativeLogicalArray.class,
-                    RDouble.class, RInteger.class, CharSXPWrapper.class};
-
-    private static final class ForeignAccessState {
-
-        private static final class TableEntry {
-            private final Class<? extends RTruffleObject> clazz; // for sanity check
-            private final ForeignAccess foreignAccess;
-
-            private TableEntry(Class<? extends RTruffleObject> clazz, ForeignAccess foreignAccess) {
-                this.clazz = clazz;
-                this.foreignAccess = foreignAccess;
-            }
-        }
-
+    private static final class TableEntry {
+        private final Class<? extends RTruffleObject> clazz; // for sanity check
+        private final ForeignAccess foreignAccess;
         /**
-         * Table with a unique index for each class in {@link #FOREIGN_CLASSES}.
-         */
-        private static Class<?>[] classTable;
-        /**
-         * Isomorphic to {@link #classTable} but contains the {@link ForeignAccess} instance.
-         */
-        private final TableEntry[] table;
-        /**
-         * Mask to efficiently compute the table index.
-         */
-        @CompilationFinal private static int tableMask;
-        /**
-         * The thread that this state is generated for.
+         * {@link PolyglotEngine} checks the thread on a {@link ForeignAccess}.
          */
         private final Thread thread;
 
-        private ForeignAccessState() {
+        private TableEntry(Class<? extends RTruffleObject> clazz, ForeignAccess foreignAccess) {
+            this.clazz = clazz;
+            this.foreignAccess = foreignAccess;
             this.thread = Thread.currentThread();
-            table = new TableEntry[classTable.length];
-            for (int i = 0; i < table.length; i++) {
-                @SuppressWarnings("unchecked")
-                Class<? extends RTruffleObject> checkedClass = (Class<? extends RTruffleObject>) classTable[i];
-                if (checkedClass != null) {
-                    table[i] = new TableEntry(checkedClass, createForeignAccess(checkedClass));
-                }
-            }
-        }
-
-        private ForeignAccess get(RTruffleObject obj) {
-            Class<? extends RTruffleObject> clazz = obj.getClass();
-            return get(clazz);
         }
+    }
 
-        private ForeignAccess get(Class<? extends RTruffleObject> clazz) {
-            int index = System.identityHashCode(clazz) & tableMask;
-            assert table[index].clazz == clazz;
-            return table[index].foreignAccess;
-        }
+    private final TableEntry[] table = new TableEntry[32];
+    int tableIndex;
 
-        static {
-            generatePrototypeTable();
-        }
-
-        /**
-         * Create a table that has a unique index for every member of {@link #FOREIGN_CLASSES} for
-         * efficient access. Since {@link System#identityHashCode(Object)} can vary from run to run,
-         * the size of the table may vary, but is typically in the range 64-4096.
-         */
-        private static void generatePrototypeTable() {
-            int ts = 32;
-            while (true) {
-                classTable = new Class<?>[ts];
-                boolean collision = false;
-                for (int i = 0; i < FOREIGN_CLASSES.length; i++) {
-                    Class<?> clazz = FOREIGN_CLASSES[i];
-                    int h = System.identityHashCode(clazz);
-                    int hc = h % ts;
-                    if (classTable[hc] == null) {
-                        classTable[hc] = clazz;
-                    } else {
-                        collision = true;
-                        break;
-                    }
-                }
-                if (!collision) {
-                    break;
-                } else {
-                    ts = ts * 2;
-                }
+    private synchronized ForeignAccess get(RTruffleObject obj) {
+        Class<? extends RTruffleObject> objclazz = obj.getClass();
+        Thread thread = Thread.currentThread();
+        for (int i = 0; i < tableIndex; i++) {
+            TableEntry te = table[i];
+            if (te.clazz == objclazz && te.thread == thread) {
+                return te.foreignAccess;
             }
-            tableMask = ts - 1;
         }
+        return createForeignAccess(objclazz);
+    }
 
-        @TruffleBoundary
-        private static ForeignAccess createForeignAccess(Class<? extends RTruffleObject> clazz) {
-            ForeignAccess foreignAccess = null;
-            String name = clazz.getSimpleName();
-            if (RNull.class.isAssignableFrom(clazz)) {
-                foreignAccess = RNullMRForeign.createAccess();
-            } else if (RList.class.isAssignableFrom(clazz)) {
-                foreignAccess = RListMRForeign.createAccess();
-            } else if (REnvironment.class.isAssignableFrom(clazz)) {
-                foreignAccess = REnvironmentMRForeign.createAccess();
-            } else if (RPairList.class.isAssignableFrom(clazz)) {
-                foreignAccess = RPairListMRForeign.createAccess();
-            } else if (RFunction.class.isAssignableFrom(clazz)) {
-                foreignAccess = RFunctionMRForeign.createAccess();
-            } else if (DLL.DLLInfo.class.isAssignableFrom(clazz)) {
-                foreignAccess = DLLInfoMRForeign.createAccess();
-            } else if (DLL.DotSymbol.class.isAssignableFrom(clazz)) {
-                foreignAccess = DLLDotSymbolMRForeign.createAccess();
-            } else if (RSymbol.class.isAssignableFrom(clazz)) {
-                foreignAccess = RSymbolMRForeign.createAccess();
-            } else if (RExternalPtr.class.isAssignableFrom(clazz)) {
-                foreignAccess = RExternalPtrMRForeign.createAccess();
-            } else if (RUnboundValue.class.isAssignableFrom(clazz)) {
-                foreignAccess = RUnboundValueMRForeign.createAccess();
-            } else if (NativeRawArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeRawArrayMRForeign.createAccess();
-            } else if (NativeLogicalArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeLogicalArrayMRForeign.createAccess();
-            } else if (NativeCharArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeCharArrayMRForeign.createAccess();
-            } else if (NativeDoubleArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeDoubleArrayMRForeign.createAccess();
-            } else if (NativeIntegerArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeIntegerArrayMRForeign.createAccess();
-            } else if (RInteger.class.isAssignableFrom(clazz)) {
-                foreignAccess = RIntegerMRForeign.createAccess();
-            } else if (RDouble.class.isAssignableFrom(clazz)) {
-                foreignAccess = RDoubleMRForeign.createAccess();
-            } else if (CharSXPWrapper.class.isAssignableFrom(clazz)) {
-                foreignAccess = CharSXPWrapperMRForeign.createAccess();
+    @TruffleBoundary
+    private static ForeignAccess createForeignAccess(Class<? extends RTruffleObject> clazz) {
+        ForeignAccess foreignAccess = null;
+        String name = clazz.getSimpleName();
+        if (RNull.class.isAssignableFrom(clazz)) {
+            foreignAccess = RNullMRForeign.createAccess();
+        } else if (RList.class.isAssignableFrom(clazz)) {
+            foreignAccess = RListMRForeign.createAccess();
+        } else if (REnvironment.class.isAssignableFrom(clazz)) {
+            foreignAccess = REnvironmentMRForeign.createAccess();
+        } else if (RPairList.class.isAssignableFrom(clazz)) {
+            foreignAccess = RPairListMRForeign.createAccess();
+        } else if (RFunction.class.isAssignableFrom(clazz)) {
+            foreignAccess = RFunctionMRForeign.createAccess();
+        } else if (DLL.DLLInfo.class.isAssignableFrom(clazz)) {
+            foreignAccess = DLLInfoMRForeign.createAccess();
+        } else if (DLL.DotSymbol.class.isAssignableFrom(clazz)) {
+            foreignAccess = DLLDotSymbolMRForeign.createAccess();
+        } else if (RSymbol.class.isAssignableFrom(clazz)) {
+            foreignAccess = RSymbolMRForeign.createAccess();
+        } else if (RExternalPtr.class.isAssignableFrom(clazz)) {
+            foreignAccess = RExternalPtrMRForeign.createAccess();
+        } else if (RUnboundValue.class.isAssignableFrom(clazz)) {
+            foreignAccess = RUnboundValueMRForeign.createAccess();
+        } else if (NativeRawArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeRawArrayMRForeign.createAccess();
+        } else if (NativeLogicalArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeLogicalArrayMRForeign.createAccess();
+        } else if (NativeCharArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeCharArrayMRForeign.createAccess();
+        } else if (NativeDoubleArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeDoubleArrayMRForeign.createAccess();
+        } else if (NativeIntegerArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeIntegerArrayMRForeign.createAccess();
+        } else if (RInteger.class.isAssignableFrom(clazz)) {
+            foreignAccess = RIntegerMRForeign.createAccess();
+        } else if (RDouble.class.isAssignableFrom(clazz)) {
+            foreignAccess = RDoubleMRForeign.createAccess();
+        } else if (CharSXPWrapper.class.isAssignableFrom(clazz)) {
+            foreignAccess = CharSXPWrapperMRForeign.createAccess();
+        } else {
+            if (RAbstractVector.class.isAssignableFrom(clazz)) {
+                foreignAccess = ForeignAccess.create(RAbstractVector.class, new RAbstractVectorAccessFactory());
             } else {
-                if (RAbstractVector.class.isAssignableFrom(clazz)) {
-                    foreignAccess = ForeignAccess.create(RAbstractVector.class, new RAbstractVectorAccessFactory());
-                } else {
-                    throw RInternalError.unimplemented("foreignAccess: " + name);
-                }
+                throw RInternalError.unimplemented("foreignAccess: " + name);
             }
-            return foreignAccess;
         }
+        return foreignAccess;
     }
 
-    /**
-     * In normal execution, there is only one thread.
-     */
-    private static final Assumption singleStateAssumption = Truffle.getRuntime().createAssumption("single ForeignAccessState");
-    /**
-     * In case of multiple threads, the per-thread state.
-     */
-    private static final ThreadLocal<ForeignAccessState> threadLocalState = new ThreadLocal<>();
-    /**
-     * In single thread mode, a fast path to the state. In multi-thread mode set to {@code null}.
-     */
-    @CompilationFinal private static ForeignAccessState singleForeignAccessState;
-
     @Override
     public ForeignAccess getForeignAccess(RTruffleObject obj) {
         CompilerAsserts.neverPartOfCompilation("getForeignAccess");
-        ForeignAccessState foreignAccessState;
-        if (singleStateAssumption.isValid()) {
-            foreignAccessState = singleForeignAccessState;
-            if (foreignAccessState == null) {
-                // very first call
-                foreignAccessState = new ForeignAccessState();
-                singleForeignAccessState = foreignAccessState;
-                threadLocalState.set(foreignAccessState);
-            } else {
-                // check thread
-                if (Thread.currentThread() != foreignAccessState.thread) {
-                    singleStateAssumption.invalidate();
-                    singleForeignAccessState = null;
-                    foreignAccessState = new ForeignAccessState();
-                }
-            }
-        } else {
-            // use the threadLocal
-            foreignAccessState = threadLocalState.get();
-        }
-        ForeignAccess result = foreignAccessState.get(obj);
-        return result;
+        return get(obj);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java
index ba772aadafd1ae5e92c821eaa469420bf0f711e6..b903c34a33b245b303024cbba5565adec471c612 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java
@@ -69,14 +69,16 @@ public class TruffleLLVM_UpCallsRFFIImpl extends UpCallsRFFIImpl implements Vari
 
     // Checkstyle: stop method name check
 
-    public Object Rf_mkCharLenCE(Object bytes, int encoding) {
+    @Override
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
         if (bytes instanceof NativeCharArray) {
-            return super.Rf_mkCharLenCE(((NativeCharArray) bytes).getBytes(), encoding);
+            return super.Rf_mkCharLenCE(((NativeCharArray) bytes).getBytes(), len, encoding);
         } else {
             throw RInternalError.unimplemented();
         }
     }
 
+    @Override
     public Object Rf_install(Object name) {
         if (name instanceof NativeCharArray) {
             return RDataFactory.createSymbolInterned(new String(((NativeCharArray) name).getBytes(), StandardCharsets.UTF_8));
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 5d57760780e479a08eff65ae183d677e4c88a9a1..92b618c6f10d6e92dcbdb2ea16f1b375b9cdb1c8 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -151,24 +151,24 @@ void init_internals(JNIEnv *env) {
 	Rf_setAttribMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_setAttrib", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 0);
 	Rf_isStringMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_isString", "(Ljava/lang/Object;)I", 0);
 	Rf_isNullMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_isNull", "(Ljava/lang/Object;)I", 0);
-	Rf_installMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_install", "(Ljava/lang/String;)Ljava/lang/Object;", 0);
-	Rf_warningMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warning", "(Ljava/lang/String;)V", 0);
-	Rf_warningcallMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warningcall", "(Ljava/lang/Object;Ljava/lang/String;)V", 0);
-	Rf_errorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_error", "(Ljava/lang/String;)V", 0);
+	Rf_installMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_install", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_warningMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warning", "(Ljava/lang/Object;)V", 0);
+	Rf_warningcallMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warningcall", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	Rf_errorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_error", "(Ljava/lang/Object;)V", 0);
 	Rf_allocateVectorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_allocateVector", "(II)Ljava/lang/Object;", 0);
 	Rf_allocateMatrixMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_allocateMatrix", "(III)Ljava/lang/Object;", 0);
 	Rf_allocateArrayMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_allocateArray", "(ILjava/lang/Object;)Ljava/lang/Object;", 0);
 	Rf_duplicateMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_duplicate", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
 	Rf_anyDuplicatedMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_anyDuplicated", "(Ljava/lang/Object;I)I", 0);
-	R_NewHashedEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;Ljava/lang/String;ZI)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 0);
+	R_NewHashedEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;I)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 0);
 	Rf_classgetsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_classgets", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
-	RprintfMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rprintf", "(Ljava/lang/String;)V", 0);
-	R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_MAKE_CLASS", "(Ljava/lang/String;)Ljava/lang/Object;", 0);
+	RprintfMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rprintf", "(Ljava/lang/Object;)V", 0);
+	R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_MAKE_CLASS", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
 	R_FindNamespaceMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_FindNamespace", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
 	R_BindingIsLockedID = checkGetMethodID(env, UpCallsRFFIClass, "R_BindingIsLocked", "(Ljava/lang/Object;Ljava/lang/Object;)I", 0);
 	Rf_GetOption1MethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_GetOption1", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
 	Rf_gsetVarMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_gsetVar", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 0);
-	Rf_inheritsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_inherits", "(Ljava/lang/Object;Ljava/lang/String;)I", 0);
+	Rf_inheritsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_inherits", "(Ljava/lang/Object;Ljava/lang/Object;)I", 0);
 	Rf_lengthgetsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_lengthgets", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
 //	Rf_rPsortMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_rPsort", "(Lcom/oracle/truffle/r/runtime/data/RDoubleVector;II)", 0);
 //	Rf_iPsortMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_iPsort", "(Lcom/oracle/truffle/r/runtime/data/RIntVector;II)", 0);
@@ -197,7 +197,7 @@ void init_internals(JNIEnv *env) {
 	Rf_asIntegerMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asInteger", "(Ljava/lang/Object;)I", 0);
 	Rf_asRealMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asReal", "(Ljava/lang/Object;)D", 0);
 	Rf_asCharMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asChar", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
-	Rf_mkCharLenCEMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_mkCharLenCE", "([BI)Ljava/lang/Object;", 0);
+	Rf_mkCharLenCEMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_mkCharLenCE", "(Ljava/lang/Object;II)Ljava/lang/Object;", 0);
 	Rf_asLogicalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asLogical", "(Ljava/lang/Object;)I", 0);
 	Rf_PairToVectorListMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_PairToVectorList", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
 	NAMED_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "NAMED", "(Ljava/lang/Object;)I", 0);
@@ -527,7 +527,7 @@ SEXP Rf_mkCharLenCE(const char *x, int len, cetype_t enc) {
 	JNIEnv *thisenv = getEnv();
 	jbyteArray bytes = (*thisenv)->NewByteArray(thisenv, len);
 	(*thisenv)->SetByteArrayRegion(thisenv, bytes, 0, len, (const jbyte *) x);
-	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_mkCharLenCEMethodID, bytes, (int) enc);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_mkCharLenCEMethodID, bytes, len, (int) enc);
 	return checkRef(thisenv, result);
 }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java
index 1c159c108c494f4d645280b917ea9c78937a6934..24b0336f2668f3b682ed2e38fa9b382879fe682e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java
@@ -29,11 +29,17 @@ import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.frame.FrameDescriptor;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CADDRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CADRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CARNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDDRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.MiscNodesFactory.LENGTHNodeGen;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.context.RContext;
 
 public final class FFIUpCallRootNode extends RootNode {
-    private static RootCallTarget[] rootCallTargets = new RootCallTarget[UpCallsIndex.TABLE_LENGTH];
+    private static RootCallTarget[] rootCallTargets = new RootCallTarget[RFFIUpCallMethod.values().length];
 
     @Child private FFIUpCallNode theFFIUpCallNode;
     private final int numArgs;
@@ -61,15 +67,29 @@ public final class FFIUpCallRootNode extends RootNode {
         }
     }
 
-    static void add(int index, Supplier<FFIUpCallNode> constructor) {
+    static void add(RFFIUpCallMethod upCallMethod, Supplier<FFIUpCallNode> constructor) {
+
         FFIUpCallRootNode rootNode = new FFIUpCallRootNode(constructor.get());
-        rootCallTargets[index] = Truffle.getRuntime().createCallTarget(rootNode);
+        rootCallTargets[upCallMethod.ordinal()] = Truffle.getRuntime().createCallTarget(rootNode);
     }
 
-    public static RootCallTarget getCallTarget(int index) {
-        RootCallTarget target = rootCallTargets[index];
+    public static RootCallTarget getCallTarget(RFFIUpCallMethod upCallMethod) {
+        RootCallTarget target = rootCallTargets[upCallMethod.ordinal()];
         assert target != null;
         return target;
     }
 
+    static void register() {
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asReal, AsRealNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asLogical, AsLogicalNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asInteger, AsIntegerNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asChar, AsCharNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CAR, CARNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CDR, CDRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CADR, CADRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CADDR, CADDRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CDDR, CDDRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.LENGTH, LENGTHNodeGen::create);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..280484b54e9225a9efbd92cc65588b8f7e6b8fca
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+
+/**
+ * Generated from {@link UpCallsRFFI}. Any native code that is dependent on the ordinal value of
+ * these enums must be kept in sync. The {@link #main} method will generate the appropriate C
+ * #define statements.
+ */
+public enum RFFIUpCallMethod {
+    CADDR("(object) : object"),
+    CADR("(object) : object"),
+    CAR("(object) : object"),
+    CDDR("(object) : object"),
+    CDR("(object) : object"),
+    DUPLICATE_ATTRIB("(object, object) : void"),
+    ENCLOS("(object) : object"),
+    GetRNGstate("() : void"),
+    INTEGER("(object) : object"),
+    IS_S4_OBJECT("(object) : sint32"),
+    LENGTH("(object) : sint32"),
+    LOGICAL("(object) : object"),
+    NAMED("(object) : sint32"),
+    OBJECT("(object) : sint32"),
+    PRINTNAME("(object) : object"),
+    PRVALUE("(object) : object"),
+    PutRNGstate("() : void"),
+    RAW("(object) : object"),
+    RDEBUG("(object) : sint32"),
+    REAL("(object) : object"),
+    RSTEP("(object) : sint32"),
+    R_BaseEnv("() : object"),
+    R_BaseNamespace("() : object"),
+    R_BindingIsLocked("(object, object) : sint32"),
+    R_CleanUp("(sint32, sint32, sint32) : void"),
+    R_ExternalPtrAddr("(object) : object"),
+    R_ExternalPtrProt("(object) : object"),
+    R_ExternalPtrTag("(object) : object"),
+    R_FindNamespace("(object) : object"),
+    R_GlobalContext("() : object"),
+    R_GlobalEnv("() : object"),
+    R_HomeDir("() : object"),
+    R_Interactive("() : sint32"),
+    R_MakeExternalPtr("(object, object, object) : object"),
+    R_NamespaceRegistry("() : object"),
+    R_NewHashedEnv("(object, sint32) : object"),
+    R_ParseVector("(object, sint32, object) : object"),
+    R_SetExternalPtrAddr("(object, object) : void"),
+    R_SetExternalPtrProt("(object, object) : void"),
+    R_SetExternalPtrTag("(object, object) : void"),
+    R_ToplevelExec("() : object"),
+    R_computeIdentical("(object, object, sint32) : sint32"),
+    R_do_MAKE_CLASS("(object) : object"),
+    R_getContextCall("(object) : object"),
+    R_getContextEnv("(object) : object"),
+    R_getContextFun("(object) : object"),
+    R_getContextSrcRef("(object) : object"),
+    R_getGlobalFunctionContext("() : object"),
+    R_getParentFunctionContext("(object) : object"),
+    R_insideBrowser("() : sint32"),
+    R_isEqual("(object, object) : sint32"),
+    R_isGlobal("(object) : sint32"),
+    R_lsInternal3("(object, sint32, sint32) : object"),
+    R_tryEval("(object, object, object) : object"),
+    Rf_GetOption1("(object) : object"),
+    Rf_PairToVectorList("(object) : object"),
+    Rf_ScalarDouble("(double) : object"),
+    Rf_ScalarInteger("(sint32) : object"),
+    Rf_ScalarLogical("(sint32) : object"),
+    Rf_ScalarString("(object) : object"),
+    Rf_allocateArray("(sint32, object) : object"),
+    Rf_allocateMatrix("(sint32, sint32, sint32) : object"),
+    Rf_allocateVector("(sint32, sint32) : object"),
+    Rf_anyDuplicated("(object, sint32) : sint32"),
+    Rf_asChar("(object) : object"),
+    Rf_asInteger("(object) : sint32"),
+    Rf_asLogical("(object) : sint32"),
+    Rf_asReal("(object) : double"),
+    Rf_classgets("(object, object) : object"),
+    Rf_cons("(object, object) : object"),
+    Rf_copyListMatrix("(object, object, sint32) : void"),
+    Rf_copyMatrix("(object, object, sint32) : void"),
+    Rf_defineVar("(object, object, object) : void"),
+    Rf_duplicate("(object, sint32) : object"),
+    Rf_error("(object) : void"),
+    Rf_eval("(object, object) : object"),
+    Rf_findVar("(object, object) : object"),
+    Rf_findVarInFrame("(object, object) : object"),
+    Rf_findVarInFrame3("(object, object, sint32) : object"),
+    Rf_findfun("(object, object) : object"),
+    Rf_getAttrib("(object, object) : object"),
+    Rf_gsetVar("(object, object, object) : void"),
+    Rf_inherits("(object, object) : sint32"),
+    Rf_install("(object) : object"),
+    Rf_isNull("(object) : sint32"),
+    Rf_isString("(object) : sint32"),
+    Rf_lengthgets("(object, sint32) : object"),
+    Rf_mkCharLenCE("(object, sint32, sint32) : object"),
+    Rf_ncols("(object) : sint32"),
+    Rf_nrows("(object) : sint32"),
+    Rf_setAttrib("(object, object, object) : void"),
+    Rf_warning("(object) : void"),
+    Rf_warningcall("(object, object) : void"),
+    Rprintf("(object) : void"),
+    SETCADR("(object, object) : object"),
+    SETCAR("(object, object) : object"),
+    SETCDR("(object, object) : object"),
+    SET_RDEBUG("(object, sint32) : void"),
+    SET_RSTEP("(object, sint32) : void"),
+    SET_STRING_ELT("(object, sint32, object) : void"),
+    SET_SYMVALUE("(object, object) : void"),
+    SET_TAG("(object, object) : object"),
+    SET_TYPEOF_FASTR("(object, sint32) : object"),
+    SET_VECTOR_ELT("(object, sint32, object) : void"),
+    STRING_ELT("(object, sint32) : object"),
+    SYMVALUE("(object) : object"),
+    TAG("(object) : object"),
+    TYPEOF("(object) : sint32"),
+    VECTOR_ELT("(object, sint32) : object"),
+    unif_rand("() : double");
+
+    /**
+     * The signature used for the upcall in Truffle NFI.
+     */
+    public final String nfiSignature;
+
+    RFFIUpCallMethod(String signature) {
+        this.nfiSignature = signature;
+    }
+
+    public static void main(String[] args) {
+        for (RFFIUpCallMethod f : RFFIUpCallMethod.values()) {
+            System.out.printf("#define %s %d\n", f.name(), f.ordinal());
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TraceUpCallsAdapter.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TraceUpCallsAdapter.java
index 2ba610c7b3796937d4ad400887ef22547e7d5bb8..2c42a92eb5bbeb27d1cc5d4124875a3fdddc3174 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TraceUpCallsAdapter.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TraceUpCallsAdapter.java
@@ -96,7 +96,7 @@ public class TraceUpCallsAdapter implements UpCallsRFFI {
     }
 
     @Override
-    public Object Rf_mkCharLenCE(byte[] bytes, int encoding) {
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
         }
@@ -119,7 +119,7 @@ public class TraceUpCallsAdapter implements UpCallsRFFI {
     }
 
     @Override
-    public Object R_do_MAKE_CLASS(String clazz) {
+    public Object R_do_MAKE_CLASS(Object clazz) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("R_do_MAKE_CLASS", clazz);
         }
@@ -166,7 +166,7 @@ public class TraceUpCallsAdapter implements UpCallsRFFI {
     }
 
     @Override
-    public int Rf_inherits(Object x, String clazz) {
+    public int Rf_inherits(Object x, Object clazz) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
         }
@@ -174,7 +174,7 @@ public class TraceUpCallsAdapter implements UpCallsRFFI {
     }
 
     @Override
-    public Object Rf_install(String name) {
+    public Object Rf_install(Object name) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rf_install", name);
         }
@@ -214,21 +214,21 @@ public class TraceUpCallsAdapter implements UpCallsRFFI {
     }
 
     @Override
-    public void Rf_error(String msg) {
+    public void Rf_error(Object msg) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rf_error", msg);
         }
     }
 
     @Override
-    public void Rf_warning(String msg) {
+    public void Rf_warning(Object msg) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rf_warning", msg);
         }
     }
 
     @Override
-    public void Rf_warningcall(Object call, String msg) {
+    public void Rf_warningcall(Object call, Object msg) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
         }
@@ -721,7 +721,7 @@ public class TraceUpCallsAdapter implements UpCallsRFFI {
     }
 
     @Override
-    public void Rprintf(String message) {
+    public void Rprintf(Object message) {
         if (RFFIUtils.traceEnabled()) {
             RFFIUtils.traceUpCall("Rprintf", message);
         }
@@ -883,9 +883,9 @@ public class TraceUpCallsAdapter implements UpCallsRFFI {
     }
 
     @Override
-    public REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
+    public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) {
         if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, name, hashed, initialSize);
+            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, initialSize);
         }
         return null;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/UpCallsIndex.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/UpCallsIndex.java
deleted file mode 100644
index 21915f44541558cce6c82ac03908fa67c8d8d500..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/UpCallsIndex.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.ffi;
-
-import com.oracle.truffle.api.RootCallTarget;
-import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CADDRNodeGen;
-import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CADRNodeGen;
-import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CARNodeGen;
-import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDDRNodeGen;
-import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDRNodeGen;
-import com.oracle.truffle.r.nodes.ffi.MiscNodesFactory.LENGTHNodeGen;
-import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
-
-/**
- * Provides indices for indexing into table of {@link RootCallTarget}s for any upcall implemented in
- * Truffle, and a {@link #register} method to associate exactly those calls which are implemented in
- * Truffle. The indices were initially generated automatically from {@link UpCallsRFFI}.
- */
-final class UpCallsIndex {
-    static final int TABLE_LENGTH = 110;
-
-    static final int CADDR = 0;
-    static final int CADR = 1;
-    static final int CAR = 2;
-    static final int CDDR = 3;
-    static final int CDR = 4;
-    static final int DUPLICATE_ATTRIB = 5;
-    static final int ENCLOS = 6;
-    static final int GetRNGstate = 7;
-    static final int INTEGER = 8;
-    static final int LENGTH = 9;
-    static final int LOGICAL = 10;
-    static final int NAMED = 11;
-    static final int OBJECT = 12;
-    static final int PRINTNAME = 13;
-    static final int PRVALUE = 14;
-    static final int PutRNGstate = 15;
-    static final int RAW = 16;
-    static final int RDEBUG = 17;
-    static final int REAL = 18;
-    static final int RSTEP = 19;
-    static final int R_BaseEnv = 20;
-    static final int R_BaseNamespace = 21;
-    static final int R_BindingIsLocked = 22;
-    static final int R_CleanUp = 23;
-    static final int R_ExternalPtrAddr = 24;
-    static final int R_ExternalPtrProt = 25;
-    static final int R_ExternalPtrTag = 26;
-    static final int R_FindNamespace = 27;
-    static final int R_GlobalContext = 28;
-    static final int R_GlobalEnv = 29;
-    static final int R_HomeDir = 30;
-    static final int R_MakeExternalPtr = 31;
-    static final int R_NamespaceRegistry = 32;
-    static final int R_NewHashedEnv = 33;
-    static final int R_ParseVector = 34;
-    static final int R_SetExternalPtrAddr = 35;
-    static final int R_SetExternalPtrProt = 36;
-    static final int R_SetExternalPtrTag = 37;
-    static final int R_ToplevelExec = 38;
-    static final int R_computeIdentical = 39;
-    static final int R_do_MAKE_CLASS = 40;
-    static final int R_getContextCall = 41;
-    static final int R_getContextEnv = 42;
-    static final int R_getContextFun = 43;
-    static final int R_getContextSrcRef = 44;
-    static final int R_getGlobalFunctionContext = 45;
-    static final int R_getParentFunctionContext = 46;
-    static final int R_insideBrowser = 47;
-    static final int R_isEqual = 48;
-    static final int R_isGlobal = 49;
-    static final int R_lsInternal3 = 50;
-    static final int R_tryEval = 51;
-    static final int Rf_GetOption1 = 52;
-    static final int Rf_PairToVectorList = 53;
-    static final int Rf_ScalarDouble = 54;
-    static final int Rf_ScalarInteger = 55;
-    static final int Rf_ScalarLogical = 56;
-    static final int Rf_ScalarString = 57;
-    static final int Rf_allocateArray = 58;
-    static final int Rf_allocateMatrix = 59;
-    static final int Rf_allocateVector = 60;
-    static final int Rf_anyDuplicated = 61;
-    static final int Rf_asChar = 62;
-    static final int Rf_asInteger = 63;
-    static final int Rf_asLogical = 64;
-    static final int Rf_asReal = 65;
-    static final int Rf_classgets = 66;
-    static final int Rf_cons = 67;
-    static final int Rf_copyListMatrix = 68;
-    static final int Rf_copyMatrix = 69;
-    static final int Rf_defineVar = 70;
-    static final int Rf_duplicate = 71;
-    static final int Rf_error = 72;
-    static final int Rf_eval = 73;
-    static final int Rf_findVar = 74;
-    static final int Rf_findVarInFrame = 75;
-    static final int Rf_findVarInFrame3 = 76;
-    static final int Rf_findfun = 77;
-    static final int Rf_getAttrib = 78;
-    static final int Rf_gsetVar = 79;
-    static final int Rf_inherits = 80;
-    static final int Rf_install = 81;
-    static final int Rf_isNull = 82;
-    static final int Rf_isString = 83;
-    static final int Rf_lengthgets = 84;
-    static final int Rf_mkCharLenCE = 85;
-    static final int Rf_ncols = 86;
-    static final int Rf_nrows = 87;
-    static final int Rf_setAttrib = 88;
-    static final int Rf_warning = 89;
-    static final int Rf_warningcall = 90;
-    static final int Rprintf = 91;
-    static final int SETCADR = 92;
-    static final int SETCAR = 93;
-    static final int SETCDR = 94;
-    static final int SET_RDEBUG = 95;
-    static final int SET_RSTEP = 96;
-    static final int SET_STRING_ELT = 97;
-    static final int SET_SYMVALUE = 98;
-    static final int SET_TAG = 99;
-    static final int SET_TYPEOF_FASTR = 100;
-    static final int SET_VECTOR_ELT = 101;
-    static final int STRING_ELT = 102;
-    static final int SYMVALUE = 103;
-    static final int TAG = 104;
-    static final int TYPEOF = 105;
-    static final int VECTOR_ELT = 106;
-    static final int R_Interactive = 107;
-    static final int isS4Object = 108;
-    static final int unif_rand = 109;
-
-    static void register() {
-        FFIUpCallRootNode.add(Rf_asReal, AsRealNodeGen::create);
-        FFIUpCallRootNode.add(Rf_asLogical, AsLogicalNodeGen::create);
-        FFIUpCallRootNode.add(Rf_asInteger, AsIntegerNodeGen::create);
-        FFIUpCallRootNode.add(Rf_asChar, AsCharNodeGen::create);
-        FFIUpCallRootNode.add(CAR, CARNodeGen::create);
-        FFIUpCallRootNode.add(CDR, CDRNodeGen::create);
-        FFIUpCallRootNode.add(CADR, CADRNodeGen::create);
-        FFIUpCallRootNode.add(CADDR, CADDRNodeGen::create);
-        FFIUpCallRootNode.add(CDDR, CDDRNodeGen::create);
-        FFIUpCallRootNode.add(LENGTH, LENGTHNodeGen::create);
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/UpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/UpCallsRFFIImpl.java
index 7668581c10e53c63d3fdc890d3d9d907e2a2752a..dca6fda9cfd1bd9e9245eb6de371502cb15c9d45 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/UpCallsRFFIImpl.java
@@ -108,7 +108,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (RFFIUtils.traceEnabled()) {
             tracer = new TraceUpCallsAdapter();
         }
-        UpCallsIndex.register();
+        FFIUpCallRootNode.register();
     }
 
     // Checkstyle: stop method name check
@@ -157,7 +157,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.Rf_asInteger(x);
         }
-        return (int) FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asInteger).call(x);
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asInteger).call(x);
     }
 
     @Override
@@ -165,7 +165,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.Rf_asReal(x);
         }
-        return (double) FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asReal).call(x);
+        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asReal).call(x);
     }
 
     @Override
@@ -173,7 +173,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.Rf_asLogical(x);
         }
-        return (int) FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asLogical).call(x);
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asLogical).call(x);
     }
 
     @Override
@@ -181,16 +181,16 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.Rf_asChar(x);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asChar).call(x);
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asChar).call(x);
     }
 
     @Override
-    public Object Rf_mkCharLenCE(byte[] bytes, int encoding) {
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
         if (tracer != null) {
-            tracer.Rf_mkCharLenCE(bytes, encoding);
+            tracer.Rf_mkCharLenCE(bytes, len, encoding);
         }
         // TODO: handle encoding properly
-        return CharSXPWrapper.create(new String(bytes, StandardCharsets.UTF_8));
+        return CharSXPWrapper.create(new String((byte[]) bytes, StandardCharsets.UTF_8));
     }
 
     @Override
@@ -216,7 +216,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public Object R_do_MAKE_CLASS(String clazz) {
+    public Object R_do_MAKE_CLASS(Object clazz) {
         if (tracer != null) {
             tracer.R_do_MAKE_CLASS(clazz);
         }
@@ -349,7 +349,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public int Rf_inherits(Object x, String clazz) {
+    public int Rf_inherits(Object x, Object clazz) {
         if (tracer != null) {
             tracer.Rf_inherits(x, clazz);
         }
@@ -364,11 +364,11 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public Object Rf_install(String name) {
+    public Object Rf_install(Object name) {
         if (tracer != null) {
             tracer.Rf_install(name);
         }
-        return RDataFactory.createSymbolInterned(name);
+        return RDataFactory.createSymbolInterned((String) name);
     }
 
     @Override
@@ -409,7 +409,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public void Rf_error(String msg) {
+    public void Rf_error(Object msg) {
         if (tracer != null) {
             tracer.Rf_error(msg);
         }
@@ -417,7 +417,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public void Rf_warning(String msg) {
+    public void Rf_warning(Object msg) {
         if (tracer != null) {
             tracer.Rf_warning(msg);
         }
@@ -425,11 +425,11 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public void Rf_warningcall(Object call, String msg) {
+    public void Rf_warningcall(Object call, Object msg) {
         if (tracer != null) {
             tracer.Rf_warningcall(call, msg);
         }
-        RErrorHandling.warningcallRFFI(call, msg);
+        RErrorHandling.warningcallRFFI(call, (String) msg);
     }
 
     @Override
@@ -536,7 +536,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.LENGTH(x);
         }
-        return (int) FFIUpCallRootNode.getCallTarget(UpCallsIndex.LENGTH).call(x);
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.LENGTH).call(x);
     }
 
     @Override
@@ -755,7 +755,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.CAR(e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CAR).call(e);
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CAR).call(e);
     }
 
     @Override
@@ -763,7 +763,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.CDR(e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CDR).call(e);
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CDR).call(e);
     }
 
     @Override
@@ -771,7 +771,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.CADR(e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CADR).call(e);
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CADR).call(e);
     }
 
     @Override
@@ -779,7 +779,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.CADDR(e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CADDR).call(e);
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CADDR).call(e);
     }
 
     @Override
@@ -787,7 +787,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
         if (tracer != null) {
             tracer.CDDR(e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CDDR).call(e);
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CDDR).call(e);
     }
 
     @Override
@@ -1224,11 +1224,11 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public void Rprintf(String message) {
+    public void Rprintf(Object message) {
         if (tracer != null) {
             tracer.Rprintf(message);
         }
-        RContext.getInstance().getConsoleHandler().print(message);
+        RContext.getInstance().getConsoleHandler().print((String) message);
     }
 
     @Override
@@ -1481,11 +1481,11 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     }
 
     @Override
-    public REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
+    public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) {
         if (tracer != null) {
-            tracer.R_NewHashedEnv(parent, name, hashed, initialSize);
+            tracer.R_NewHashedEnv(parent, initialSize);
         }
-        REnvironment env = RDataFactory.createNewEnv(name, hashed, initialSize);
+        REnvironment env = RDataFactory.createNewEnv(REnvironment.UNNAMED, true, initialSize);
         RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
         return env;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java
index 057cfaaba71e78bf7ddc0033b84d788b0532d424..f39602135479b03085dc3d774a27aefe60f7b3d9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java
@@ -39,6 +39,10 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  * writing. From the GNU R perspective all {@code Object} parameters are {@code SEXP} instances.
  * Some of the functions are typed with a specific return type but, again, this is a {@code SEXP} in
  * GNU R terms. The native side does not require a specific Java type.
+ *
+ * N.B. It is important not to be too specific about types owing the support for Truffle interop
+ * implementations. For example, many arguments are "strings" but we do not specify them as
+ * {@code String} here.
  */
 public interface StdUpCallsRFFI {
     // Checkstyle: stop method name check
@@ -59,13 +63,13 @@ public interface StdUpCallsRFFI {
 
     Object Rf_asChar(Object x);
 
-    Object Rf_mkCharLenCE(byte[] bytes, int encoding);
+    Object Rf_mkCharLenCE(Object bytes, int len, int encoding);
 
     Object Rf_cons(Object car, Object cdr);
 
     void Rf_defineVar(Object symbolArg, Object value, Object envArg);
 
-    Object R_do_MAKE_CLASS(String clazz);
+    Object R_do_MAKE_CLASS(Object clazz);
 
     /**
      * WARNING: argument order reversed from Rf_findVarInFrame!
@@ -80,9 +84,9 @@ public interface StdUpCallsRFFI {
 
     void Rf_setAttrib(Object obj, Object name, Object val);
 
-    int Rf_inherits(Object x, String clazz);
+    int Rf_inherits(Object x, Object clazz);
 
-    Object Rf_install(String name);
+    Object Rf_install(Object name);
 
     Object Rf_lengthgets(Object x, int newSize);
 
@@ -92,11 +96,11 @@ public interface StdUpCallsRFFI {
 
     Object Rf_PairToVectorList(Object x);
 
-    void Rf_error(String msg);
+    void Rf_error(Object msg);
 
-    void Rf_warning(String msg);
+    void Rf_warning(Object msg);
 
-    void Rf_warningcall(Object call, String msg);
+    void Rf_warningcall(Object call, Object msg);
 
     Object Rf_allocateVector(int mode, int n);
 
@@ -208,7 +212,7 @@ public interface StdUpCallsRFFI {
 
     int IS_S4_OBJECT(Object x);
 
-    void Rprintf(String message);
+    void Rprintf(Object message);
 
     void GetRNGstate();
 
@@ -234,6 +238,6 @@ public interface StdUpCallsRFFI {
 
     void R_CleanUp(int sa, int status, int runlast);
 
-    REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize);
+    REnvironment R_NewHashedEnv(REnvironment parent, int initialSize);
 
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9a7a0a5dcda166fdef346a6e17ecb33d8781388
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.tools;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import com.oracle.truffle.r.nodes.ffi.RFFIUpCallMethod;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+
+/**
+ * Generates the entries for {@link RFFIUpCallMethod}.
+ */
+public class RFFIUpCallMethodGenerate {
+
+    public static void main(String[] args) {
+        Method[] methods = UpCallsRFFI.class.getMethods();
+
+        Arrays.sort(methods, new Comparator<Method>() {
+
+            @Override
+            public int compare(Method a, Method b) {
+                return a.getName().compareTo(b.getName());
+            }
+
+        });
+        for (int i = 0; i < methods.length; i++) {
+            Method m = methods[i];
+            String sig = getNFISignature(m);
+            System.out.printf("%s(\"%s\")%s%n", m.getName(), sig, i == methods.length - 1 ? ";" : ",");
+        }
+
+    }
+
+    private static String getNFISignature(Method m) {
+        Class<?>[] paramTypes = m.getParameterTypes();
+        StringBuilder sb = new StringBuilder();
+        sb.append('(');
+        for (int i = 0; i < paramTypes.length; i++) {
+            Class<?> paramType = paramTypes[i];
+            String nfiParam = nfiParamName(paramType);
+            sb.append(nfiParam);
+            if (i != paramTypes.length - 1) {
+                sb.append(", ");
+            }
+        }
+        sb.append(')');
+        sb.append(" : ");
+        sb.append(nfiParamName(m.getReturnType()));
+        return sb.toString();
+    }
+
+    static String nfiParamName(Class<?> paramType) {
+        String paramName = paramType.getSimpleName();
+        switch (paramName) {
+            case "Object":
+                return "object";
+            case "int":
+                return "sint32";
+            case "double":
+                return "double";
+            case "void":
+                return "void";
+            default:
+                return "object";
+        }
+
+    }
+
+}