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..d5f87c515079f54d6310322924b28f21b450b839 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.engine.interop.NativeIntegerArray;
 import com.oracle.truffle.r.engine.interop.NativeLogicalArray;
 import com.oracle.truffle.r.engine.interop.NativeRawArray;
 import com.oracle.truffle.r.nodes.ffi.RFFIUtils;
-import com.oracle.truffle.r.nodes.ffi.UpCallsRFFIImpl;
+import com.oracle.truffle.r.nodes.ffi.JavaUpCallsRFFIImpl;
 import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -47,10 +47,10 @@ import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
 
 /**
- * (Incomplete) Variant of {@link UpCallsRFFIImpl} for Truffle LLVM.
+ * (Incomplete) Variant of {@link JavaUpCallsRFFIImpl} for Truffle LLVM.
  *
  */
-public class TruffleLLVM_UpCallsRFFIImpl extends UpCallsRFFIImpl implements VariableUpCallsRFFI {
+public class TruffleLLVM_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl implements VariableUpCallsRFFI {
     private static TruffleLLVM_UpCallsRFFIImpl singleton;
     private static TruffleObject singletonTruffleObject;
 
@@ -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..6cd1f9fe0e8c635adc38406c9c9cdcd95d5a8572 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 final 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/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..8441fc32c7dec2c65d0a48bd48be67c685ac538c
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
@@ -0,0 +1,1145 @@
+/*
+ * Copyright (c) 2014, 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 static com.oracle.truffle.r.nodes.ffi.RFFIUtils.*;
+
+import java.nio.charset.StandardCharsets;
+import java.util.function.Function;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.frame.Frame;
+import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
+import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.nodes.ffi.ParseResult.ParseStatus;
+import com.oracle.truffle.r.runtime.RArguments;
+import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.RCleanUp;
+import com.oracle.truffle.r.runtime.REnvVars;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RErrorHandling;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.RSource;
+import com.oracle.truffle.r.runtime.RSrcref;
+import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.Utils;
+import com.oracle.truffle.r.runtime.context.Engine.ParseException;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RComplexVector;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDoubleSequence;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExpression;
+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.RLanguage;
+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.RPromise;
+import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.RRawVector;
+import com.oracle.truffle.r.runtime.data.RS4Object;
+import com.oracle.truffle.r.runtime.data.RSequence;
+import com.oracle.truffle.r.runtime.data.RShareable;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.RUnboundValue;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
+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.CharSXPWrapper;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
+import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
+import com.oracle.truffle.r.runtime.nodes.RNode;
+import com.oracle.truffle.r.runtime.rng.RRNG;
+
+/**
+ * This class provides a simple Java-based implementation of {@link UpCallsRFFI}, where all the
+ * argument values are standarde Java types, i.e. no special types used by Truffle NFI or Truffle
+ * LLVM.
+ *
+ * TODO Many of the implementations here are incomplete and/or duplicate code that exists in the
+ * Truffle side of the implementation, i.e., {@link RNode} subclasses. A complete refactoring that
+ * accesses the Truffle implementations (possibly somewhat refactored owing to the fact that the
+ * Truffle side is driven by the builtins yet these functions don't not always map 1-1 to a builtin)
+ * is desirable. In some cases it may be possible to "implement" the functions in R (which is a
+ * simple way to achieve the above).
+ */
+public class JavaUpCallsRFFIImpl implements UpCallsRFFI {
+
+    // Checkstyle: stop method name check
+
+    @Override
+    public RIntVector Rf_ScalarInteger(int value) {
+        return RDataFactory.createIntVectorFromScalar(value);
+    }
+
+    @Override
+    public RLogicalVector Rf_ScalarLogical(int value) {
+        byte byteValue;
+        if (value == RRuntime.INT_NA) {
+            byteValue = RRuntime.LOGICAL_NA;
+        } else {
+            byteValue = (byte) (value & 0xFF);
+        }
+        return RDataFactory.createLogicalVectorFromScalar(byteValue);
+    }
+
+    @Override
+    public RDoubleVector Rf_ScalarDouble(double value) {
+        return RDataFactory.createDoubleVectorFromScalar(value);
+    }
+
+    @Override
+    public RStringVector Rf_ScalarString(Object value) {
+        CharSXPWrapper chars = guaranteeInstanceOf(value, CharSXPWrapper.class);
+        return RDataFactory.createStringVectorFromScalar(chars.getContents());
+    }
+
+    @Override
+    public int Rf_asInteger(Object x) {
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asInteger).call(x);
+    }
+
+    @Override
+    public double Rf_asReal(Object x) {
+        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asReal).call(x);
+    }
+
+    @Override
+    public int Rf_asLogical(Object x) {
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asLogical).call(x);
+    }
+
+    @Override
+    public Object Rf_asChar(Object x) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asChar).call(x);
+    }
+
+    @Override
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
+        // TODO: handle encoding properly
+        return CharSXPWrapper.create(new String((byte[]) bytes, StandardCharsets.UTF_8));
+    }
+
+    @Override
+    public Object Rf_cons(Object car, Object cdr) {
+        return RDataFactory.createPairList(car, cdr);
+    }
+
+    @Override
+    public void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
+        REnvironment env = (REnvironment) envArg;
+        RSymbol name = (RSymbol) symbolArg;
+        try {
+            env.put(name.getName(), value);
+        } catch (PutException ex) {
+            throw RError.error(RError.SHOW_CALLER2, ex);
+        }
+    }
+
+    @Override
+    public Object R_do_MAKE_CLASS(Object clazz) {
+        String name = "getClass";
+        RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
+        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz);
+    }
+
+    @Override
+    public Object Rf_findVar(Object symbolArg, Object envArg) {
+        return findVarInFrameHelper(envArg, symbolArg, true);
+    }
+
+    @Override
+    public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
+        return findVarInFrameHelper(envArg, symbolArg, false);
+    }
+
+    @Override
+    public Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet) {
+        // GNU R has code for IS_USER_DATBASE that uses doGet
+        // This is a lookup in the single environment (envArg) only, i.e. inherits=false
+        return findVarInFrameHelper(envArg, symbolArg, false);
+    }
+
+    private static Object findVarInFrameHelper(Object envArg, Object symbolArg, boolean inherits) {
+        if (envArg == RNull.instance) {
+            throw RError.error(RError.SHOW_CALLER2, RError.Message.USE_NULL_ENV_DEFUNCT);
+        }
+        if (!(envArg instanceof REnvironment)) {
+            throw RError.error(RError.SHOW_CALLER2, RError.Message.ARG_NOT_AN_ENVIRONMENT, inherits ? "findVar" : "findVarInFrame");
+        }
+        RSymbol name = (RSymbol) symbolArg;
+        REnvironment env = (REnvironment) envArg;
+        while (env != REnvironment.emptyEnv()) {
+            Object value = env.get(name.getName());
+            if (value != null) {
+                return value;
+            }
+            if (!inherits) {
+                // simgle frame lookup
+                break;
+            }
+            env = env.getParent();
+        }
+        return RUnboundValue.instance;
+    }
+
+    @Override
+    public Object Rf_getAttrib(Object obj, Object name) {
+        Object result = RNull.instance;
+        if (obj instanceof RAttributable) {
+            RAttributable attrObj = (RAttributable) obj;
+            DynamicObject attrs = attrObj.getAttributes();
+            if (attrs != null) {
+                String nameAsString = ((RSymbol) name).getName().intern();
+                Object attr = attrs.get(nameAsString);
+                if (attr != null) {
+                    result = attr;
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    @TruffleBoundary
+    public void Rf_setAttrib(Object obj, Object name, Object val) {
+        if (obj instanceof RAttributable) {
+            RAttributable attrObj = (RAttributable) obj;
+            String nameAsString;
+            if (name instanceof RSymbol) {
+                nameAsString = ((RSymbol) name).getName();
+            } else {
+                nameAsString = RRuntime.asString(name);
+                assert nameAsString != null;
+            }
+            nameAsString = nameAsString.intern();
+            if (val == RNull.instance) {
+                removeAttr(attrObj, nameAsString);
+            } else if ("class" == nameAsString) {
+                attrObj.initAttributes().define(nameAsString, val);
+            } else {
+                attrObj.setAttr(nameAsString, val);
+            }
+        }
+    }
+
+    @TruffleBoundary
+    private static void removeAttr(RAttributable a, String name) {
+        a.removeAttr(name);
+    }
+
+    public static RStringVector getClassHr(Object v) {
+        RStringVector result;
+        if (v instanceof RAttributable) {
+            result = ((RAttributable) v).getClassHierarchy();
+        } else if (v instanceof Byte) {
+            result = RLogicalVector.implicitClassHeader;
+        } else if (v instanceof String) {
+            result = RStringVector.implicitClassHeader;
+        } else if (v instanceof Integer) {
+            result = RIntVector.implicitClassHeader;
+        } else if (v instanceof Double) {
+            result = RDoubleVector.implicitClassHeader;
+        } else if (v instanceof RComplex) {
+            result = RComplexVector.implicitClassHeader;
+        } else if (v instanceof RRaw) {
+            result = RRawVector.implicitClassHeader;
+        } else {
+            guaranteeInstanceOf(v, RNull.class);
+            result = RNull.implicitClassHeader;
+        }
+        return result;
+    }
+
+    @Override
+    public int Rf_inherits(Object x, Object clazz) {
+        int result = 0;
+        RStringVector hierarchy = getClassHr(x);
+        for (int i = 0; i < hierarchy.getLength(); i++) {
+            if (hierarchy.getDataAt(i).equals(clazz)) {
+                result = 1;
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public Object Rf_install(Object name) {
+        return RDataFactory.createSymbolInterned((String) name);
+    }
+
+    @Override
+    public Object Rf_lengthgets(Object x, int newSize) {
+        RAbstractVector vec = (RAbstractVector) RRuntime.asAbstractVector(x);
+        return vec.resize(newSize);
+    }
+
+    @Override
+    public int Rf_isString(Object x) {
+        return RRuntime.checkType(x, RType.Character) ? 1 : 0;
+    }
+
+    @Override
+    public int Rf_isNull(Object x) {
+        return x == RNull.instance ? 1 : 0;
+    }
+
+    @Override
+    public Object Rf_PairToVectorList(Object x) {
+        if (x == RNull.instance) {
+            return RDataFactory.createList();
+        }
+        RPairList pl = (RPairList) x;
+        return pl.toRList();
+    }
+
+    @Override
+    public void Rf_error(Object msg) {
+        throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
+    }
+
+    @Override
+    public void Rf_warning(Object msg) {
+        RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
+    }
+
+    @Override
+    public void Rf_warningcall(Object call, Object msg) {
+        RErrorHandling.warningcallRFFI(call, (String) msg);
+    }
+
+    @Override
+    public Object Rf_allocateVector(int mode, int n) {
+        SEXPTYPE type = SEXPTYPE.mapInt(mode);
+        if (n < 0) {
+            throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
+            // TODO check long vector
+        }
+        switch (type) {
+            case INTSXP:
+                return RDataFactory.createIntVector(new int[n], RDataFactory.COMPLETE_VECTOR);
+            case REALSXP:
+                return RDataFactory.createDoubleVector(new double[n], RDataFactory.COMPLETE_VECTOR);
+            case LGLSXP:
+                return RDataFactory.createLogicalVector(new byte[n], RDataFactory.COMPLETE_VECTOR);
+            case STRSXP:
+                return RDataFactory.createStringVector(new String[n], RDataFactory.COMPLETE_VECTOR);
+            case CPLXSXP:
+                return RDataFactory.createComplexVector(new double[2 * n], RDataFactory.COMPLETE_VECTOR);
+            case RAWSXP:
+                return RDataFactory.createRawVector(new byte[n]);
+            case VECSXP:
+                return RDataFactory.createList(n);
+            case LANGSXP:
+                return RDataFactory.createLangPairList(n);
+            default:
+                throw unimplemented("unexpected SEXPTYPE " + type);
+        }
+    }
+
+    @Override
+    public Object Rf_allocateArray(int mode, Object dimsObj) {
+        RIntVector dims = (RIntVector) dimsObj;
+        int n = 1;
+        int[] newDims = new int[dims.getLength()];
+        // TODO check long vector
+        for (int i = 0; i < newDims.length; i++) {
+            newDims[i] = dims.getDataAt(i);
+            n *= newDims[i];
+        }
+        RAbstractVector result = (RAbstractVector) Rf_allocateVector(mode, n);
+        setDims(newDims, result);
+        return result;
+
+    }
+
+    @TruffleBoundary
+    private static void setDims(int[] newDims, RAbstractVector result) {
+        result.setDimensions(newDims);
+    }
+
+    @Override
+    public Object Rf_allocateMatrix(int mode, int nrow, int ncol) {
+        SEXPTYPE type = SEXPTYPE.mapInt(mode);
+        if (nrow < 0 || ncol < 0) {
+            throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_EXTENTS_TO_MATRIX);
+        }
+        // TODO check long vector
+        int[] dims = new int[]{nrow, ncol};
+        switch (type) {
+            case INTSXP:
+                return RDataFactory.createIntVector(new int[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
+            case REALSXP:
+                return RDataFactory.createDoubleVector(new double[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
+            case LGLSXP:
+                return RDataFactory.createLogicalVector(new byte[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
+            case STRSXP:
+                return RDataFactory.createStringVector(new String[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
+            case CPLXSXP:
+                return RDataFactory.createComplexVector(new double[2 * (nrow * ncol)], RDataFactory.COMPLETE_VECTOR, dims);
+            default:
+                throw unimplemented();
+        }
+    }
+
+    @Override
+    public int Rf_nrows(Object x) {
+        return RRuntime.nrows(x);
+    }
+
+    @Override
+    public int Rf_ncols(Object x) {
+        return RRuntime.ncols(x);
+    }
+
+    @Override
+    public int LENGTH(Object x) {
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.LENGTH).call(x);
+    }
+
+    @Override
+    public void SET_STRING_ELT(Object x, int i, Object v) {
+        RStringVector vector = guaranteeInstanceOf(x, RStringVector.class);
+        CharSXPWrapper element = guaranteeInstanceOf(v, CharSXPWrapper.class);
+        vector.setElement(i, element.getContents());
+    }
+
+    @Override
+    public void SET_VECTOR_ELT(Object x, int i, Object v) {
+        RList list = guaranteeInstanceOf(x, RList.class);
+        list.setElement(i, v);
+    }
+
+    @Override
+    public Object RAW(Object x) {
+        if (x instanceof RRawVector) {
+            return ((RRawVector) x).getDataWithoutCopying();
+        } else if (x instanceof RRaw) {
+            return new byte[]{((RRaw) x).getValue()};
+        } else {
+            throw unimplemented();
+        }
+    }
+
+    @Override
+    public Object LOGICAL(Object x) {
+        if (x instanceof RLogicalVector) {
+            return ((RLogicalVector) x).getDataWithoutCopying();
+        } else if (x instanceof Byte) {
+            return new byte[]{(Byte) x};
+        } else {
+            throw unimplemented();
+        }
+    }
+
+    @Override
+    public Object INTEGER(Object x) {
+        if (x instanceof RIntVector) {
+            return ((RIntVector) x).getDataWithoutCopying();
+        } else if (x instanceof RIntSequence) {
+            return ((RIntSequence) x).materialize().getDataWithoutCopying();
+        } else if (x instanceof Integer) {
+            return new int[]{(Integer) x};
+        } else if (x instanceof RLogicalVector) {
+            RLogicalVector vec = (RLogicalVector) x;
+            int[] result = new int[vec.getLength()];
+            for (int i = 0; i < result.length; i++) {
+                result[i] = vec.getDataAt(i);
+            }
+            return result;
+        } else {
+            guaranteeInstanceOf(x, Byte.class);
+            return new int[]{(Byte) x};
+        }
+    }
+
+    @Override
+    public Object REAL(Object x) {
+        if (x instanceof RDoubleVector) {
+            return ((RDoubleVector) x).getDataWithoutCopying();
+        } else if (x instanceof RDoubleSequence) {
+            return ((RDoubleSequence) x).materialize().getDataWithoutCopying();
+        } else {
+            guaranteeInstanceOf(x, Double.class);
+            return new double[]{(Double) x};
+        }
+    }
+
+    @Override
+    public Object STRING_ELT(Object x, int i) {
+        RAbstractStringVector vector = guaranteeInstanceOf(RRuntime.asAbstractVector(x), RAbstractStringVector.class);
+        return CharSXPWrapper.create(vector.getDataAt(i));
+    }
+
+    @Override
+    public Object VECTOR_ELT(Object x, int i) {
+        Object vec = x;
+        if (vec instanceof RExpression) {
+            return ((RExpression) vec).getDataAt(i);
+        }
+        RAbstractListVector list = guaranteeInstanceOf(RRuntime.asAbstractVector(vec), RAbstractListVector.class);
+        return list.getDataAt(i);
+    }
+
+    @Override
+    public int NAMED(Object x) {
+        if (x instanceof RShareable) {
+            return ((RShareable) x).isShared() ? 1 : 0;
+        } else {
+            throw unimplemented();
+        }
+    }
+
+    @Override
+    public Object SET_TYPEOF_FASTR(Object x, int v) {
+        int code = SEXPTYPE.gnuRCodeForObject(x);
+        if (code == SEXPTYPE.LISTSXP.code && v == SEXPTYPE.LANGSXP.code) {
+            return RLanguage.fromList(x, RLanguage.RepType.CALL);
+        } else {
+            throw unimplemented();
+        }
+    }
+
+    @Override
+    public int TYPEOF(Object x) {
+        if (x instanceof CharSXPWrapper) {
+            return SEXPTYPE.CHARSXP.code;
+        } else {
+            return SEXPTYPE.gnuRCodeForObject(x);
+        }
+    }
+
+    @Override
+    @TruffleBoundary
+    public int OBJECT(Object x) {
+        if (x instanceof RAttributable) {
+            return ((RAttributable) x).getAttr(RRuntime.CLASS_ATTR_KEY) == null ? 0 : 1;
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public Object Rf_duplicate(Object x, int deep) {
+        guarantee(x != null, "unexpected type: null instead of " + x.getClass().getSimpleName());
+        guarantee(x instanceof RShareable || x instanceof RSequence || x instanceof RExternalPtr,
+                        "unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of RShareable or RExternalPtr");
+        if (x instanceof RShareable) {
+            return deep == 1 ? ((RShareable) x).deepCopy() : ((RShareable) x).copy();
+        } else if (x instanceof RSequence) {
+            return ((RSequence) x).materializeToShareable();
+        } else {
+            return ((RExternalPtr) x).copy();
+        }
+    }
+
+    @Override
+    public int Rf_anyDuplicated(Object x, int fromLast) {
+        RAbstractVector vec = (RAbstractVector) x;
+        if (vec.getLength() == 0) {
+            return 0;
+        } else {
+            return DuplicationHelper.analyze(vec, null, true, fromLast != 0).getIndex();
+        }
+    }
+
+    @Override
+    public Object PRINTNAME(Object x) {
+        guaranteeInstanceOf(x, RSymbol.class);
+        return CharSXPWrapper.create(((RSymbol) x).getName());
+    }
+
+    @Override
+    public Object TAG(Object e) {
+        if (e instanceof RPairList) {
+            return ((RPairList) e).getTag();
+        } else {
+            guaranteeInstanceOf(e, RExternalPtr.class);
+            // at the moment, this can only be used to null out the pointer
+            return ((RExternalPtr) e).getTag();
+        }
+    }
+
+    @Override
+    public Object CAR(Object e) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CAR).call(e);
+    }
+
+    @Override
+    public Object CDR(Object e) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CDR).call(e);
+    }
+
+    @Override
+    public Object CADR(Object e) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CADR).call(e);
+    }
+
+    @Override
+    public Object CADDR(Object e) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CADDR).call(e);
+    }
+
+    @Override
+    public Object CDDR(Object e) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CDDR).call(e);
+    }
+
+    @Override
+    public Object SET_TAG(Object x, Object y) {
+        if (x instanceof RPairList) {
+            ((RPairList) x).setTag(y);
+        } else {
+            guaranteeInstanceOf(x, RExternalPtr.class);
+            // at the moment, this can only be used to null out the pointer
+            ((RExternalPtr) x).setTag(y);
+        }
+        return y;
+    }
+
+    @Override
+    public Object SETCAR(Object x, Object y) {
+        guaranteeInstanceOf(x, RPairList.class);
+        ((RPairList) x).setCar(y);
+        return y;
+    }
+
+    @Override
+    public Object SETCDR(Object x, Object y) {
+        guaranteeInstanceOf(x, RPairList.class);
+        ((RPairList) x).setCdr(y);
+        return y;
+    }
+
+    @Override
+    public Object SETCADR(Object x, Object y) {
+        SETCAR(CDR(x), y);
+        return y;
+    }
+
+    @Override
+    public Object SYMVALUE(Object x) {
+        if (!(x instanceof RSymbol)) {
+            throw RInternalError.shouldNotReachHere();
+        }
+        Object res = REnvironment.baseEnv().get(((RSymbol) x).getName());
+        if (res == null) {
+            return RUnboundValue.instance;
+        } else {
+            return res;
+        }
+    }
+
+    @Override
+    public void SET_SYMVALUE(Object x, Object v) {
+        if (!(x instanceof RSymbol)) {
+            throw RInternalError.shouldNotReachHere();
+        }
+        REnvironment.baseEnv().safePut(((RSymbol) x).getName(), v);
+    }
+
+    @Override
+    public int R_BindingIsLocked(Object sym, Object env) {
+        guaranteeInstanceOf(sym, RSymbol.class);
+        guaranteeInstanceOf(env, REnvironment.class);
+        return ((REnvironment) env).bindingIsLocked(((RSymbol) sym).getName()) ? 1 : 0;
+    }
+
+    @Override
+    public Object R_FindNamespace(Object name) {
+        Object result = RContext.getInstance().stateREnvironment.getNamespaceRegistry().get(RRuntime.asString(name));
+        return result;
+    }
+
+    @Override
+    public Object Rf_eval(Object expr, Object env) {
+        guarantee(env instanceof REnvironment);
+        Object result;
+        if (expr instanceof RPromise) {
+            result = RContext.getRRuntimeASTAccess().forcePromise(null, expr);
+        } else if (expr instanceof RExpression) {
+            result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, RCaller.topLevel);
+        } else if (expr instanceof RLanguage) {
+            result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, RCaller.topLevel);
+        } else if (expr instanceof RPairList) {
+            RPairList l = (RPairList) expr;
+            RFunction f = (RFunction) l.car();
+            Object args = l.cdr();
+            if (args == RNull.instance) {
+                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, null, new Object[0]);
+            } else {
+                RList argsList = ((RPairList) args).toRList();
+                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, argsList.getNames(),
+                                argsList.getDataNonShared());
+            }
+        } else {
+            // just return value
+            result = expr;
+        }
+        return result;
+    }
+
+    @Override
+    public Object Rf_findfun(Object symbolObj, Object envObj) {
+        guarantee(envObj instanceof REnvironment);
+        REnvironment env = (REnvironment) envObj;
+        guarantee(symbolObj instanceof RSymbol);
+        RSymbol symbol = (RSymbol) symbolObj;
+        // Works but not remotely efficient
+        Source source = RSource.fromTextInternal("get(\"" + symbol.getName() + "\", mode=\"function\")", RSource.Internal.RF_FINDFUN);
+        try {
+            Object result = RContext.getEngine().parseAndEval(source, env.getFrame(), false);
+            return result;
+        } catch (ParseException ex) {
+            throw RInternalError.shouldNotReachHere(ex);
+        }
+    }
+
+    @Override
+    public Object Rf_GetOption1(Object tag) {
+        guarantee(tag instanceof RSymbol);
+        Object result = RContext.getInstance().stateROptions.getValue(((RSymbol) tag).getName());
+        return result;
+    }
+
+    @Override
+    public void Rf_gsetVar(Object symbol, Object value, Object rho) {
+        guarantee(symbol instanceof RSymbol);
+        REnvironment baseEnv = RContext.getInstance().stateREnvironment.getBaseEnv();
+        guarantee(rho == baseEnv);
+        try {
+            baseEnv.put(((RSymbol) symbol).getName(), value);
+        } catch (PutException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void DUPLICATE_ATTRIB(Object to, Object from) {
+        if (from instanceof RAttributable) {
+            guaranteeInstanceOf(to, RAttributable.class);
+            DynamicObject attributes = ((RAttributable) from).getAttributes();
+            ((RAttributable) to).initAttributes(attributes == null ? null : RAttributesLayout.copy(attributes));
+        }
+        // TODO: copy OBJECT? and S4 attributes
+    }
+
+    @Override
+    public int R_computeIdentical(Object x, Object y, int flags) {
+        RFunction indenticalBuiltin = RContext.lookupBuiltin("identical");
+        Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
+                        RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0))));
+        return (int) res;
+    }
+
+    @Override
+    public void Rf_copyListMatrix(Object s, Object t, int byrow) {
+        throw unimplemented();
+    }
+
+    @Override
+    public void Rf_copyMatrix(Object s, Object t, int byrow) {
+        throw unimplemented();
+    }
+
+    @Override
+    public Object R_tryEval(Object expr, Object env, boolean silent) {
+        Object handlerStack = RErrorHandling.getHandlerStack();
+        Object restartStack = RErrorHandling.getRestartStack();
+        try {
+            // TODO handle silent
+            RErrorHandling.resetStacks();
+            Object result = Rf_eval(expr, env);
+            return result;
+        } catch (Throwable t) {
+            return null;
+        } finally {
+            RErrorHandling.restoreStacks(handlerStack, restartStack);
+        }
+    }
+
+    /**
+     * 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.
+     */
+    @Override
+    public Object R_ToplevelExec() {
+        return RErrorHandling.resetAndGetHandlerStacks();
+    }
+
+    @Override
+    public int RDEBUG(Object x) {
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        if (env instanceof REnvironment.Function) {
+            REnvironment.Function funcEnv = (REnvironment.Function) env;
+            RFunction func = RArguments.getFunction(funcEnv.getFrame());
+            return RContext.getRRuntimeASTAccess().isDebugged(func) ? 1 : 0;
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public void SET_RDEBUG(Object x, int v) {
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        if (env instanceof REnvironment.Function) {
+            REnvironment.Function funcEnv = (REnvironment.Function) env;
+            RFunction func = RArguments.getFunction(funcEnv.getFrame());
+            if (v == 1) {
+                RContext.getRRuntimeASTAccess().enableDebug(func, false);
+            } else {
+                RContext.getRRuntimeASTAccess().disableDebug(func);
+            }
+        }
+    }
+
+    @Override
+    public int RSTEP(Object x) {
+        @SuppressWarnings("unused")
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        throw RInternalError.unimplemented("RSTEP");
+    }
+
+    @Override
+    public void SET_RSTEP(Object x, int v) {
+        @SuppressWarnings("unused")
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        throw RInternalError.unimplemented("SET_RSTEP");
+    }
+
+    @Override
+    public Object ENCLOS(Object x) {
+        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
+        Object result = env.getParent();
+        if (result == null) {
+            result = RNull.instance;
+        }
+        return result;
+    }
+
+    @Override
+    public Object PRVALUE(Object x) {
+        RPromise p = guaranteeInstanceOf(x, RPromise.class);
+        return p.isEvaluated() ? p.getValue() : RUnboundValue.instance;
+    }
+
+    @Override
+    public Object R_ParseVector(Object text, int n, Object srcFile) {
+        // TODO general case
+        assert n == 1;
+        assert srcFile == RNull.instance;
+        String textString = RRuntime.asString(text);
+        assert textString != null;
+
+        try {
+            Source source = RSource.fromTextInternal(textString, RSource.Internal.R_PARSEVECTOR);
+            RExpression exprs = RContext.getEngine().parse(source);
+            return new ParseResult(ParseStatus.PARSE_OK.ordinal(), exprs);
+        } catch (ParseException ex) {
+            // TODO incomplete
+            return new ParseResult(ParseStatus.PARSE_ERROR.ordinal(), RNull.instance);
+        }
+    }
+
+    @Override
+    public Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
+        boolean sorted = sortedArg != 0;
+        boolean all = allArg != 0;
+        REnvironment env = guaranteeInstanceOf(envArg, REnvironment.class);
+        return env.ls(all, null, sorted);
+    }
+
+    @Override
+    public String R_HomeDir() {
+        return REnvVars.rHome();
+    }
+
+    @Override
+    public void R_CleanUp(int sa, int status, int runlast) {
+        RCleanUp.stdCleanUp(SA_TYPE.values()[sa], status, runlast != 0);
+    }
+
+    @Override
+    public Object R_GlobalContext() {
+        Utils.warn("Potential memory leak (global context object)");
+        Frame frame = Utils.getActualCurrentFrame();
+        if (frame == null) {
+            return RCaller.topLevel;
+        }
+        if (RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser()) {
+            return RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller();
+        }
+        RCaller rCaller = RArguments.getCall(frame);
+        return rCaller == null ? RCaller.topLevel : rCaller;
+    }
+
+    @Override
+    public Object R_GlobalEnv() {
+        return RContext.getInstance().stateREnvironment.getGlobalEnv();
+    }
+
+    @Override
+    public Object R_BaseEnv() {
+        return RContext.getInstance().stateREnvironment.getBaseEnv();
+    }
+
+    @Override
+    public Object R_BaseNamespace() {
+        return RContext.getInstance().stateREnvironment.getBaseNamespace();
+    }
+
+    @Override
+    public Object R_NamespaceRegistry() {
+        return RContext.getInstance().stateREnvironment.getNamespaceRegistry();
+    }
+
+    @Override
+    public int R_Interactive() {
+        return RContext.getInstance().isInteractive() ? 1 : 0;
+    }
+
+    @Override
+    public int IS_S4_OBJECT(Object x) {
+        return x instanceof RS4Object ? 1 : 0;
+    }
+
+    @Override
+    public void Rprintf(Object message) {
+        RContext.getInstance().getConsoleHandler().print((String) message);
+    }
+
+    @Override
+    public void GetRNGstate() {
+        RRNG.getRNGState();
+    }
+
+    @Override
+    public void PutRNGstate() {
+        RRNG.putRNGState();
+    }
+
+    @Override
+    public double unif_rand() {
+        return RRNG.unifRand();
+    }
+
+    // Checkstyle: stop method name check
+
+    @Override
+    public Object R_getGlobalFunctionContext() {
+        Utils.warn("Potential memory leak (global function context object)");
+        Frame frame = Utils.getActualCurrentFrame();
+        if (frame == null) {
+            return RNull.instance;
+        }
+        RCaller currentCaller = RArguments.getCall(frame);
+        while (currentCaller != null) {
+            if (!currentCaller.isPromise() && currentCaller.isValidCaller() && currentCaller != RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller()) {
+                break;
+            }
+            currentCaller = currentCaller.getParent();
+        }
+        return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller;
+    }
+
+    @Override
+    public Object R_getParentFunctionContext(Object c) {
+        Utils.warn("Potential memory leak (parent function context object)");
+        RCaller currentCaller = guaranteeInstanceOf(c, RCaller.class);
+        while (true) {
+            currentCaller = currentCaller.getParent();
+            if (currentCaller == null ||
+                            (!currentCaller.isPromise() && currentCaller.isValidCaller() && currentCaller != RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller())) {
+                break;
+            }
+        }
+        return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller;
+    }
+
+    @Override
+    public Object R_getContextEnv(Object c) {
+        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
+        if (rCaller == RCaller.topLevel) {
+            return RContext.getInstance().stateREnvironment.getGlobalEnv();
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        if (RArguments.getCall(frame) == rCaller) {
+            return REnvironment.frameToEnvironment(frame.materialize());
+        } else {
+            Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
+
+                @Override
+                public Object apply(Frame f) {
+                    RCaller currentCaller = RArguments.getCall(f);
+                    if (currentCaller == rCaller) {
+                        return REnvironment.frameToEnvironment(f.materialize());
+                    } else {
+                        return null;
+                    }
+                }
+            });
+            return result;
+        }
+    }
+
+    @Override
+    public Object R_getContextFun(Object c) {
+        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
+        if (rCaller == RCaller.topLevel) {
+            return RNull.instance;
+        }
+        Frame frame = Utils.getActualCurrentFrame();
+        if (RArguments.getCall(frame) == rCaller) {
+            return RArguments.getFunction(frame);
+        } else {
+            Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
+
+                @Override
+                public Object apply(Frame f) {
+                    RCaller currentCaller = RArguments.getCall(f);
+                    if (currentCaller == rCaller) {
+                        return RArguments.getFunction(f);
+                    } else {
+                        return null;
+                    }
+                }
+            });
+            return result;
+        }
+    }
+
+    @Override
+    public Object R_getContextCall(Object c) {
+        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
+        if (rCaller == RCaller.topLevel) {
+            return RNull.instance;
+        }
+        return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller);
+    }
+
+    @Override
+    public Object R_getContextSrcRef(Object c) {
+        Object o = R_getContextFun(c);
+        if (!(o instanceof RFunction)) {
+            return RNull.instance;
+        } else {
+            RFunction f = (RFunction) o;
+            SourceSection ss = f.getRootNode().getSourceSection();
+            String path = RSource.getPath(ss.getSource());
+            // TODO: is it OK to pass "" if path is null?
+            return RSrcref.createLloc(ss, path == null ? "" : path);
+        }
+    }
+
+    @Override
+    public int R_insideBrowser() {
+        return RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser() ? 1 : 0;
+    }
+
+    @Override
+    public int R_isGlobal(Object c) {
+        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
+
+        return rCaller == RCaller.topLevel ? 1 : 0;
+    }
+
+    @Override
+    public int R_isEqual(Object x, Object y) {
+        return x == y ? 1 : 0;
+    }
+
+    @Override
+    @TruffleBoundary
+    public Object Rf_classgets(Object x, Object y) {
+        RAbstractVector vector = guaranteeInstanceOf(x, RAbstractVector.class);
+        vector.setClassAttr(guaranteeInstanceOf(y, RStringVector.class));
+        return RNull.instance;
+    }
+
+    @Override
+    public RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
+        return RDataFactory.createExternalPtr(new SymbolHandle(addr), tag, prot);
+    }
+
+    @Override
+    public long R_ExternalPtrAddr(Object x) {
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        return p.getAddr().asAddress();
+    }
+
+    @Override
+    public Object R_ExternalPtrTag(Object x) {
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        return p.getTag();
+    }
+
+    @Override
+    public Object R_ExternalPtrProt(Object x) {
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        return p.getProt();
+    }
+
+    @Override
+    public void R_SetExternalPtrAddr(Object x, long addr) {
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        p.setAddr(new SymbolHandle(addr));
+    }
+
+    @Override
+    public void R_SetExternalPtrTag(Object x, Object tag) {
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        p.setTag(tag);
+    }
+
+    @Override
+    public void R_SetExternalPtrProt(Object x, Object prot) {
+        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
+        p.setProt(prot);
+    }
+
+    @Override
+    public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) {
+        REnvironment env = RDataFactory.createNewEnv(REnvironment.UNNAMED, true, initialSize);
+        RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
+        return env;
+    }
+
+}
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..fc354a931de72d93a2b997e4c3d9bf0011a529b5
--- /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("(pointer) : 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("(pointer) : 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("(pointer, object) : sint32"),
+    Rf_install("(pointer) : object"),
+    Rf_isNull("(object) : sint32"),
+    Rf_isString("(object) : sint32"),
+    Rf_lengthgets("(object, sint32) : object"),
+    Rf_mkCharLenCE("(pointer, sint32, sint32) : object"),
+    Rf_ncols("(object) : sint32"),
+    Rf_nrows("(object) : sint32"),
+    Rf_setAttrib("(object, object, object) : void"),
+    Rf_warning("(pointer) : void"),
+    Rf_warningcall("(object, pointer) : void"),
+    Rprintf("(pointer) : 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_x %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
deleted file mode 100644
index 2ba610c7b3796937d4ad400887ef22547e7d5bb8..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TraceUpCallsAdapter.java
+++ /dev/null
@@ -1,892 +0,0 @@
-/*
- * Copyright (c) 2016, 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.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RExternalPtr;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
-
-public class TraceUpCallsAdapter implements UpCallsRFFI {
-    @Override
-    public RIntVector Rf_ScalarInteger(int value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
-        }
-        return null;
-    }
-
-    @Override
-    public RLogicalVector Rf_ScalarLogical(int value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
-        }
-        return null;
-    }
-
-    @Override
-    public RDoubleVector Rf_ScalarDouble(double value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
-        }
-        return null;
-    }
-
-    @Override
-    public RStringVector Rf_ScalarString(Object value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarString", value);
-        }
-        return null;
-    }
-
-    @Override
-    public int Rf_asInteger(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asInteger", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public double Rf_asReal(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asReal", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public int Rf_asLogical(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asLogical", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object Rf_asChar(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asChar", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_mkCharLenCE(byte[] bytes, int encoding) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_cons(Object car, Object cdr) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_cons", car, cdr);
-        }
-        return null;
-    }
-
-    @Override
-    public void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
-        }
-    }
-
-    @Override
-    public Object R_do_MAKE_CLASS(String clazz) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_do_MAKE_CLASS", clazz);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_findVar(Object symbolArg, Object envArg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findVarInFrame", envArg, symbolArg);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_getAttrib(Object obj, Object name) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
-        }
-        return null;
-    }
-
-    @Override
-    public void Rf_setAttrib(Object obj, Object name, Object val) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_setAttrib", obj, name, val);
-        }
-    }
-
-    @Override
-    public int Rf_inherits(Object x, String clazz) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object Rf_install(String name) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_install", name);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_lengthgets(Object x, int newSize) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
-        }
-        return null;
-    }
-
-    @Override
-    public int Rf_isString(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_isString", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public int Rf_isNull(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_isNull", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object Rf_PairToVectorList(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
-        }
-        return null;
-    }
-
-    @Override
-    public void Rf_error(String msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_error", msg);
-        }
-    }
-
-    @Override
-    public void Rf_warning(String msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_warning", msg);
-        }
-    }
-
-    @Override
-    public void Rf_warningcall(Object call, String msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
-        }
-    }
-
-    @Override
-    public Object Rf_allocateVector(int mode, int n) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_allocateArray(int mode, Object dimsObj) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_allocateMatrix(int mode, int nrow, int ncol) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
-        }
-        return null;
-    }
-
-    @Override
-    public int Rf_nrows(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_nrows", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public int Rf_ncols(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ncols", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public int LENGTH(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("LENGTH", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public void SET_STRING_ELT(Object x, int i, Object v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
-        }
-    }
-
-    @Override
-    public void SET_VECTOR_ELT(Object x, int i, Object v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
-        }
-    }
-
-    @Override
-    public Object RAW(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("RAW", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object LOGICAL(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("LOGICAL", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object INTEGER(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("INTEGER", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object REAL(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("REAL", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object STRING_ELT(Object x, int i) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("STRING_ELT", x, i);
-        }
-        return null;
-    }
-
-    @Override
-    public Object VECTOR_ELT(Object x, int i) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
-        }
-        return null;
-    }
-
-    @Override
-    public int NAMED(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("NAMED", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object SET_TYPEOF_FASTR(Object x, int v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
-        }
-        return null;
-    }
-
-    @Override
-    public int TYPEOF(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("TYPEOF", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public int OBJECT(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("OBJECT", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object Rf_duplicate(Object x, int deep) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_duplicate", x, deep);
-        }
-        return null;
-    }
-
-    @Override
-    public int Rf_anyDuplicated(Object x, int fromLast) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object PRINTNAME(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("PRINTNAME", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object TAG(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("TAG", e);
-        }
-        return null;
-    }
-
-    @Override
-    public Object CAR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CAR", e);
-        }
-        return null;
-    }
-
-    @Override
-    public Object CDR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CDR", e);
-        }
-        return null;
-    }
-
-    @Override
-    public Object CADR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CADR", e);
-        }
-        return null;
-    }
-
-    @Override
-    public Object CADDR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CADDR", e);
-        }
-        return null;
-    }
-
-    @Override
-    public Object CDDR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CDDR", e);
-        }
-        return null;
-    }
-
-    @Override
-    public Object SET_TAG(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_TAG", x, y);
-        }
-        return null;
-    }
-
-    @Override
-    public Object SETCAR(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SETCAR", x, y);
-        }
-        return null;
-    }
-
-    @Override
-    public Object SETCDR(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SETCDR", x, y);
-        }
-        return null;
-    }
-
-    @Override
-    public Object SETCADR(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SETCADR", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object SYMVALUE(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SYMVALUE", x);
-        }
-        return null;
-    }
-
-    @Override
-    public void SET_SYMVALUE(Object x, Object v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
-        }
-    }
-
-    @Override
-    public int R_BindingIsLocked(Object sym, Object env) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_BindingIsLocked", sym, env);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object R_FindNamespace(Object name) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_FindNamespace", name);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_eval(Object expr, Object env) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_eval", expr, env);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_findfun(Object symbolObj, Object envObj) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
-        }
-        return null;
-    }
-
-    @Override
-    public Object Rf_GetOption1(Object tag) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_GetOption1", tag);
-        }
-        return null;
-    }
-
-    @Override
-    public void Rf_gsetVar(Object symbol, Object value, Object rho) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
-        }
-    }
-
-    @Override
-    public void DUPLICATE_ATTRIB(Object to, Object from) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
-        }
-    }
-
-    @Override
-    public int R_computeIdentical(Object x, Object y, int flags) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
-        }
-        return 0;
-    }
-
-    @Override
-    public void Rf_copyListMatrix(Object s, Object t, int byrow) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
-        }
-    }
-
-    @Override
-    public void Rf_copyMatrix(Object s, Object t, int byrow) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
-        }
-    }
-
-    @Override
-    public Object R_tryEval(Object expr, Object env, boolean silent) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_ToplevelExec() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_TopLevelExec");
-        }
-        return null;
-    }
-
-    @Override
-    public int RDEBUG(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("RDEBUG", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public void SET_RDEBUG(Object x, int v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
-        }
-    }
-
-    @Override
-    public int RSTEP(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("RSTEP", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public void SET_RSTEP(Object x, int v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_RSTEP", x, v);
-        }
-    }
-
-    @Override
-    public Object ENCLOS(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("ENCLOS", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object PRVALUE(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("PRVALUE", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_ParseVector(Object text, int n, Object srcFile) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ParseVector", text, n, srcFile);
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_lsInternal3", envArg, allArg, sortedArg);
-        }
-        return null;
-    }
-
-    @Override
-    public String R_HomeDir() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_HomeDir");
-        }
-        return null;
-    }
-
-    @Override
-    public void R_CleanUp(int sa, int status, int runlast) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_Cleanup", sa, status, runlast);
-        }
-    }
-
-    @Override
-    public Object R_GlobalContext() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_GlobalContext");
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_GlobalEnv() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_GlobalEnv");
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_BaseEnv() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_BaseEnv");
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_BaseNamespace() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_BaseNamespace");
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_NamespaceRegistry() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_NamespaceRegistry");
-        }
-        return null;
-    }
-
-    @Override
-    public int R_Interactive() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("isInteractive");
-        }
-        return 0;
-    }
-
-    @Override
-    public int IS_S4_OBJECT(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("isS4Object");
-        }
-        return 0;
-    }
-
-    @Override
-    public void Rprintf(String message) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rprintf", message);
-        }
-    }
-
-    @Override
-    public void GetRNGstate() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("GetRNGstate");
-        }
-    }
-
-    @Override
-    public void PutRNGstate() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("PutRNGstate");
-        }
-    }
-
-    @Override
-    public double unif_rand() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("unif_rand");
-        }
-        return 0;
-    }
-
-    @Override
-    public Object R_getGlobalFunctionContext() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_getGlobalFunctionContext");
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_getParentFunctionContext(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_getParentFunctionContext");
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_getContextEnv(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_getContextEnv", c);
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_getContextFun(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_getContextFun", c);
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_getContextCall(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_getContextCall", c);
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_getContextSrcRef(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_getContextSrcRef", c);
-        }
-        return null;
-    }
-
-    @Override
-    public int R_insideBrowser() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_insideBrowser");
-        }
-        return 0;
-    }
-
-    @Override
-    public int R_isGlobal(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_isGlobal", c);
-        }
-        return 0;
-    }
-
-    @Override
-    public int R_isEqual(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("isEqual", x, y);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object Rf_classgets(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_classgets", x, y);
-        }
-        return null;
-    }
-
-    @Override
-    public RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_MakeExternalPtr", addr, tag, prot);
-        }
-        return null;
-    }
-
-    @Override
-    public long R_ExternalPtrAddr(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrAddr", x);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object R_ExternalPtrTag(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrTag", x);
-        }
-        return null;
-    }
-
-    @Override
-    public Object R_ExternalPtrProt(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
-        }
-        return null;
-    }
-
-    @Override
-    public void R_SetExternalPtrAddr(Object x, long addr) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_SetExternalPtrAddr", x);
-        }
-    }
-
-    @Override
-    public void R_SetExternalPtrTag(Object x, Object tag) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_SetExternalPtrTag", x);
-        }
-    }
-
-    @Override
-    public void R_SetExternalPtrProt(Object x, Object prot) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
-        }
-    }
-
-    @Override
-    public REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, name, hashed, 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..59a0dbc1390adbfc6f9c1ebe90fffe5874ce4235 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -22,1480 +22,928 @@
  */
 package com.oracle.truffle.r.nodes.ffi;
 
-import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.*;
-
-import java.nio.charset.StandardCharsets;
-import java.util.function.Function;
-
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.frame.Frame;
-import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
-import com.oracle.truffle.api.object.DynamicObject;
-import com.oracle.truffle.api.source.Source;
-import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.ffi.ParseResult.ParseStatus;
-import com.oracle.truffle.r.runtime.RArguments;
-import com.oracle.truffle.r.runtime.RCaller;
-import com.oracle.truffle.r.runtime.RCleanUp;
-import com.oracle.truffle.r.runtime.REnvVars;
-import com.oracle.truffle.r.runtime.RError;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.guaranteeInstanceOf;
+
 import com.oracle.truffle.r.runtime.RErrorHandling;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.RSource;
-import com.oracle.truffle.r.runtime.RSrcref;
-import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
-import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.context.Engine.ParseException;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RDoubleSequence;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RExpression;
 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.RLanguage;
-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.RPromise;
-import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RRawVector;
-import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RSequence;
-import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RSymbol;
-import com.oracle.truffle.r.runtime.data.RUnboundValue;
 import com.oracle.truffle.r.runtime.data.RVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
-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.CharSXPWrapper;
 import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
-import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
-import com.oracle.truffle.r.runtime.nodes.RNode;
-import com.oracle.truffle.r.runtime.rng.RRNG;
-
-/**
- * This class provides a simple Java-based implementation of {@link UpCallsRFFI}, using no Truffle
- * mechanisms.
- *
- * TODO Many of the implementations here are incomplete and/or duplicate code that exists in the
- * Truffle side of the implementation, i.e., {@link RNode} subclasses. A complete refactoring that
- * accesses the Truffle implementations (possibly somewhat refactored owing to the fact that the
- * Truffle side is driven by the builtins yet these functions don't not always map 1-1 to a builtin)
- * is desirable. In some cases it may be possible to "implement" the functions in R (which is a
- * simple way to achieve the above).
- */
-public class UpCallsRFFIImpl implements UpCallsRFFI {
 
-    protected TraceUpCallsAdapter tracer;
+public final class UpCallsRFFIImpl implements UpCallsRFFI {
+    // Checkstyle: stop method name check
 
-    public UpCallsRFFIImpl() {
-        if (RFFIUtils.traceEnabled()) {
-            tracer = new TraceUpCallsAdapter();
-        }
-        UpCallsIndex.register();
-    }
+    private final UpCallsRFFI delegate;
+    private final boolean tracing;
 
-    // Checkstyle: stop method name check
+    public UpCallsRFFIImpl(UpCallsRFFI delegate) {
+        this.delegate = delegate;
+        FFIUpCallRootNode.register();
+        tracing = RFFIUtils.traceEnabled();
+    }
 
     @Override
     public RIntVector Rf_ScalarInteger(int value) {
-        if (tracer != null) {
-            tracer.Rf_ScalarInteger(value);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
         }
-        return RDataFactory.createIntVectorFromScalar(value);
+        return delegate.Rf_ScalarInteger(value);
     }
 
     @Override
     public RLogicalVector Rf_ScalarLogical(int value) {
-        if (tracer != null) {
-            tracer.Rf_ScalarLogical(value);
-        }
-        byte byteValue;
-        if (value == RRuntime.INT_NA) {
-            byteValue = RRuntime.LOGICAL_NA;
-        } else {
-            byteValue = (byte) (value & 0xFF);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
         }
-        return RDataFactory.createLogicalVectorFromScalar(byteValue);
+        return delegate.Rf_ScalarLogical(value);
     }
 
     @Override
     public RDoubleVector Rf_ScalarDouble(double value) {
-        if (tracer != null) {
-            tracer.Rf_ScalarDouble(value);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
         }
-        return RDataFactory.createDoubleVectorFromScalar(value);
+        return delegate.Rf_ScalarDouble(value);
     }
 
     @Override
     public RStringVector Rf_ScalarString(Object value) {
-        if (tracer != null) {
-            tracer.Rf_ScalarString(value);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_ScalarString", value);
         }
-        CharSXPWrapper chars = guaranteeInstanceOf(value, CharSXPWrapper.class);
-        return RDataFactory.createStringVectorFromScalar(chars.getContents());
+        return delegate.Rf_ScalarString(value);
     }
 
     @Override
     public int Rf_asInteger(Object x) {
-        if (tracer != null) {
-            tracer.Rf_asInteger(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_asInteger", x);
         }
-        return (int) FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asInteger).call(x);
+        return delegate.Rf_asInteger(x);
     }
 
     @Override
     public double Rf_asReal(Object x) {
-        if (tracer != null) {
-            tracer.Rf_asReal(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_asReal", x);
         }
-        return (double) FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asReal).call(x);
+        return delegate.Rf_asReal(x);
     }
 
     @Override
     public int Rf_asLogical(Object x) {
-        if (tracer != null) {
-            tracer.Rf_asLogical(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_asLogical", x);
         }
-        return (int) FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asLogical).call(x);
+        return delegate.Rf_asLogical(x);
     }
 
     @Override
     public Object Rf_asChar(Object x) {
-        if (tracer != null) {
-            tracer.Rf_asChar(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_asChar", x);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.Rf_asChar).call(x);
+        return delegate.Rf_asChar(x);
     }
 
     @Override
-    public Object Rf_mkCharLenCE(byte[] bytes, int encoding) {
-        if (tracer != null) {
-            tracer.Rf_mkCharLenCE(bytes, encoding);
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
         }
-        // TODO: handle encoding properly
-        return CharSXPWrapper.create(new String(bytes, StandardCharsets.UTF_8));
+        return delegate.Rf_mkCharLenCE(bytes, len, encoding);
     }
 
     @Override
     public Object Rf_cons(Object car, Object cdr) {
-        if (tracer != null) {
-            tracer.Rf_cons(car, cdr);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_cons", car, cdr);
         }
-        return RDataFactory.createPairList(car, cdr);
+        return delegate.Rf_cons(car, cdr);
     }
 
     @Override
     public void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
-        if (tracer != null) {
-            tracer.Rf_defineVar(symbolArg, value, envArg);
-        }
-        REnvironment env = (REnvironment) envArg;
-        RSymbol name = (RSymbol) symbolArg;
-        try {
-            env.put(name.getName(), value);
-        } catch (PutException ex) {
-            throw RError.error(RError.SHOW_CALLER2, ex);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
         }
+        delegate.Rf_defineVar(symbolArg, value, envArg);
     }
 
     @Override
-    public Object R_do_MAKE_CLASS(String clazz) {
-        if (tracer != null) {
-            tracer.R_do_MAKE_CLASS(clazz);
+    public Object R_do_MAKE_CLASS(Object clazz) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_do_MAKE_CLASS", clazz);
         }
-        String name = "getClass";
-        RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
-        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz);
+        return delegate.R_do_MAKE_CLASS(clazz);
     }
 
     @Override
     public Object Rf_findVar(Object symbolArg, Object envArg) {
-        if (tracer != null) {
-            tracer.Rf_findVar(symbolArg, envArg);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
         }
-        return findVarInFrameHelper(envArg, symbolArg, true);
+        return delegate.Rf_findVar(symbolArg, envArg);
     }
 
     @Override
     public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
-        if (tracer != null) {
-            tracer.Rf_findVarInFrame(envArg, symbolArg);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_findVarInFrame", envArg, symbolArg);
         }
-        return findVarInFrameHelper(envArg, symbolArg, false);
+        return delegate.Rf_findVarInFrame(envArg, symbolArg);
     }
 
     @Override
     public Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet) {
-        if (tracer != null) {
-            tracer.Rf_findVarInFrame3(envArg, symbolArg, doGet);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
         }
-        // GNU R has code for IS_USER_DATBASE that uses doGet
-        // This is a lookup in the single environment (envArg) only, i.e. inherits=false
-        return findVarInFrameHelper(envArg, symbolArg, false);
-    }
-
-    private static Object findVarInFrameHelper(Object envArg, Object symbolArg, boolean inherits) {
-        if (envArg == RNull.instance) {
-            throw RError.error(RError.SHOW_CALLER2, RError.Message.USE_NULL_ENV_DEFUNCT);
-        }
-        if (!(envArg instanceof REnvironment)) {
-            throw RError.error(RError.SHOW_CALLER2, RError.Message.ARG_NOT_AN_ENVIRONMENT, inherits ? "findVar" : "findVarInFrame");
-        }
-        RSymbol name = (RSymbol) symbolArg;
-        REnvironment env = (REnvironment) envArg;
-        while (env != REnvironment.emptyEnv()) {
-            Object value = env.get(name.getName());
-            if (value != null) {
-                return value;
-            }
-            if (!inherits) {
-                // simgle frame lookup
-                break;
-            }
-            env = env.getParent();
-        }
-        return RUnboundValue.instance;
+        return delegate.Rf_findVarInFrame3(envArg, symbolArg, doGet);
     }
 
     @Override
     public Object Rf_getAttrib(Object obj, Object name) {
-        if (tracer != null) {
-            tracer.Rf_getAttrib(obj, name);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
         }
-        Object result = RNull.instance;
-        if (obj instanceof RAttributable) {
-            RAttributable attrObj = (RAttributable) obj;
-            DynamicObject attrs = attrObj.getAttributes();
-            if (attrs != null) {
-                String nameAsString = ((RSymbol) name).getName().intern();
-                Object attr = attrs.get(nameAsString);
-                if (attr != null) {
-                    result = attr;
-                }
-            }
-        }
-        return result;
+        return delegate.Rf_getAttrib(obj, name);
     }
 
     @Override
-    @TruffleBoundary
     public void Rf_setAttrib(Object obj, Object name, Object val) {
-        if (tracer != null) {
-            tracer.Rf_setAttrib(obj, name, val);
-        }
-        if (obj instanceof RAttributable) {
-            RAttributable attrObj = (RAttributable) obj;
-            String nameAsString;
-            if (name instanceof RSymbol) {
-                nameAsString = ((RSymbol) name).getName();
-            } else {
-                nameAsString = RRuntime.asString(name);
-                assert nameAsString != null;
-            }
-            nameAsString = nameAsString.intern();
-            if (val == RNull.instance) {
-                removeAttr(attrObj, nameAsString);
-            } else if ("class" == nameAsString) {
-                attrObj.initAttributes().define(nameAsString, val);
-            } else {
-                attrObj.setAttr(nameAsString, val);
-            }
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_setAttrib", obj, name, val);
         }
-    }
-
-    @TruffleBoundary
-    private static void removeAttr(RAttributable a, String name) {
-        a.removeAttr(name);
-    }
-
-    public static RStringVector getClassHr(Object v) {
-        RStringVector result;
-        if (v instanceof RAttributable) {
-            result = ((RAttributable) v).getClassHierarchy();
-        } else if (v instanceof Byte) {
-            result = RLogicalVector.implicitClassHeader;
-        } else if (v instanceof String) {
-            result = RStringVector.implicitClassHeader;
-        } else if (v instanceof Integer) {
-            result = RIntVector.implicitClassHeader;
-        } else if (v instanceof Double) {
-            result = RDoubleVector.implicitClassHeader;
-        } else if (v instanceof RComplex) {
-            result = RComplexVector.implicitClassHeader;
-        } else if (v instanceof RRaw) {
-            result = RRawVector.implicitClassHeader;
-        } else {
-            guaranteeInstanceOf(v, RNull.class);
-            result = RNull.implicitClassHeader;
-        }
-        return result;
+        delegate.Rf_setAttrib(obj, name, val);
     }
 
     @Override
-    public int Rf_inherits(Object x, String clazz) {
-        if (tracer != null) {
-            tracer.Rf_inherits(x, clazz);
-        }
-        int result = 0;
-        RStringVector hierarchy = getClassHr(x);
-        for (int i = 0; i < hierarchy.getLength(); i++) {
-            if (hierarchy.getDataAt(i).equals(clazz)) {
-                result = 1;
-            }
+    public int Rf_inherits(Object x, Object clazz) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
         }
-        return result;
+        return delegate.Rf_inherits(x, clazz);
     }
 
     @Override
-    public Object Rf_install(String name) {
-        if (tracer != null) {
-            tracer.Rf_install(name);
+    public Object Rf_install(Object name) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_install", name);
         }
-        return RDataFactory.createSymbolInterned(name);
+        return delegate.Rf_install(name);
     }
 
     @Override
     public Object Rf_lengthgets(Object x, int newSize) {
-        if (tracer != null) {
-            tracer.Rf_lengthgets(x, newSize);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
         }
-        RAbstractVector vec = (RAbstractVector) RRuntime.asAbstractVector(x);
-        return vec.resize(newSize);
+        return delegate.Rf_lengthgets(x, newSize);
     }
 
     @Override
     public int Rf_isString(Object x) {
-        if (tracer != null) {
-            tracer.Rf_isString(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_isString", x);
         }
-        return RRuntime.checkType(x, RType.Character) ? 1 : 0;
+        return delegate.Rf_isString(x);
     }
 
     @Override
     public int Rf_isNull(Object x) {
-        if (tracer != null) {
-            tracer.Rf_isNull(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_isNull", x);
         }
-        return x == RNull.instance ? 1 : 0;
+        return delegate.Rf_isNull(x);
     }
 
     @Override
     public Object Rf_PairToVectorList(Object x) {
-        if (tracer != null) {
-            tracer.Rf_PairToVectorList(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
         }
-        if (x == RNull.instance) {
-            return RDataFactory.createList();
-        }
-        RPairList pl = (RPairList) x;
-        return pl.toRList();
+        return delegate.Rf_PairToVectorList(x);
     }
 
     @Override
-    public void Rf_error(String msg) {
-        if (tracer != null) {
-            tracer.Rf_error(msg);
+    public void Rf_error(Object msg) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_error", msg);
         }
-        throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
+        delegate.Rf_error(msg);
     }
 
     @Override
-    public void Rf_warning(String msg) {
-        if (tracer != null) {
-            tracer.Rf_warning(msg);
+    public void Rf_warning(Object msg) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_warning", msg);
         }
-        RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
+        delegate.Rf_warning(msg);
     }
 
     @Override
-    public void Rf_warningcall(Object call, String msg) {
-        if (tracer != null) {
-            tracer.Rf_warningcall(call, msg);
+    public void Rf_warningcall(Object call, Object msg) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
         }
-        RErrorHandling.warningcallRFFI(call, msg);
+        delegate.Rf_warningcall(call, msg);
     }
 
     @Override
     public Object Rf_allocateVector(int mode, int n) {
-        if (tracer != null) {
-            tracer.Rf_allocateVector(mode, n);
-        }
-        SEXPTYPE type = SEXPTYPE.mapInt(mode);
-        if (n < 0) {
-            throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
-            // TODO check long vector
-        }
-        switch (type) {
-            case INTSXP:
-                return RDataFactory.createIntVector(new int[n], RDataFactory.COMPLETE_VECTOR);
-            case REALSXP:
-                return RDataFactory.createDoubleVector(new double[n], RDataFactory.COMPLETE_VECTOR);
-            case LGLSXP:
-                return RDataFactory.createLogicalVector(new byte[n], RDataFactory.COMPLETE_VECTOR);
-            case STRSXP:
-                return RDataFactory.createStringVector(new String[n], RDataFactory.COMPLETE_VECTOR);
-            case CPLXSXP:
-                return RDataFactory.createComplexVector(new double[2 * n], RDataFactory.COMPLETE_VECTOR);
-            case RAWSXP:
-                return RDataFactory.createRawVector(new byte[n]);
-            case VECSXP:
-                return RDataFactory.createList(n);
-            case LANGSXP:
-                return RDataFactory.createLangPairList(n);
-            default:
-                throw unimplemented("unexpected SEXPTYPE " + type);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
         }
+        return delegate.Rf_allocateVector(mode, n);
     }
 
     @Override
     public Object Rf_allocateArray(int mode, Object dimsObj) {
-        if (tracer != null) {
-            tracer.Rf_allocateArray(mode, dimsObj);
-        }
-        RIntVector dims = (RIntVector) dimsObj;
-        int n = 1;
-        int[] newDims = new int[dims.getLength()];
-        // TODO check long vector
-        for (int i = 0; i < newDims.length; i++) {
-            newDims[i] = dims.getDataAt(i);
-            n *= newDims[i];
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
         }
-        RAbstractVector result = (RAbstractVector) Rf_allocateVector(mode, n);
-        setDims(newDims, result);
-        return result;
-
-    }
-
-    @TruffleBoundary
-    private static void setDims(int[] newDims, RAbstractVector result) {
-        result.setDimensions(newDims);
+        return null;
     }
 
     @Override
     public Object Rf_allocateMatrix(int mode, int nrow, int ncol) {
-        if (tracer != null) {
-            tracer.Rf_allocateMatrix(mode, ncol, nrow);
-        }
-        SEXPTYPE type = SEXPTYPE.mapInt(mode);
-        if (nrow < 0 || ncol < 0) {
-            throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_EXTENTS_TO_MATRIX);
-        }
-        // TODO check long vector
-        int[] dims = new int[]{nrow, ncol};
-        switch (type) {
-            case INTSXP:
-                return RDataFactory.createIntVector(new int[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
-            case REALSXP:
-                return RDataFactory.createDoubleVector(new double[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
-            case LGLSXP:
-                return RDataFactory.createLogicalVector(new byte[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
-            case STRSXP:
-                return RDataFactory.createStringVector(new String[nrow * ncol], RDataFactory.COMPLETE_VECTOR, dims);
-            case CPLXSXP:
-                return RDataFactory.createComplexVector(new double[2 * (nrow * ncol)], RDataFactory.COMPLETE_VECTOR, dims);
-            default:
-                throw unimplemented();
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
         }
+        return delegate.Rf_allocateMatrix(mode, nrow, ncol);
     }
 
     @Override
     public int Rf_nrows(Object x) {
-        if (tracer != null) {
-            tracer.Rf_nrows(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_nrows", x);
         }
-        return RRuntime.nrows(x);
+        return delegate.Rf_nrows(x);
     }
 
     @Override
     public int Rf_ncols(Object x) {
-        if (tracer != null) {
-            tracer.Rf_ncols(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_ncols", x);
         }
-        return RRuntime.ncols(x);
+        return delegate.Rf_ncols(x);
     }
 
     @Override
     public int LENGTH(Object x) {
-        if (tracer != null) {
-            tracer.LENGTH(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("LENGTH", x);
         }
-        return (int) FFIUpCallRootNode.getCallTarget(UpCallsIndex.LENGTH).call(x);
+        return delegate.LENGTH(x);
     }
 
     @Override
     public void SET_STRING_ELT(Object x, int i, Object v) {
-        if (tracer != null) {
-            tracer.SET_STRING_ELT(x, i, v);
+        if (tracing) {
+            RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
         }
-        RStringVector vector = guaranteeInstanceOf(x, RStringVector.class);
-        CharSXPWrapper element = guaranteeInstanceOf(v, CharSXPWrapper.class);
-        vector.setElement(i, element.getContents());
+        delegate.SET_STRING_ELT(x, i, v);
     }
 
     @Override
     public void SET_VECTOR_ELT(Object x, int i, Object v) {
-        if (tracer != null) {
-            tracer.SET_VECTOR_ELT(x, i, v);
+        if (tracing) {
+            RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
         }
-        RList list = guaranteeInstanceOf(x, RList.class);
-        list.setElement(i, v);
+        delegate.SET_VECTOR_ELT(x, i, v);
     }
 
     @Override
     public Object RAW(Object x) {
-        if (tracer != null) {
-            tracer.RAW(x);
-        }
-        if (x instanceof RRawVector) {
-            return ((RRawVector) x).getDataWithoutCopying();
-        } else if (x instanceof RRaw) {
-            return new byte[]{((RRaw) x).getValue()};
-        } else {
-            throw unimplemented();
+        if (tracing) {
+            RFFIUtils.traceUpCall("RAW", x);
         }
+        return delegate.RAW(x);
     }
 
     @Override
     public Object LOGICAL(Object x) {
-        if (tracer != null) {
-            tracer.LOGICAL(x);
-        }
-        if (x instanceof RLogicalVector) {
-            return ((RLogicalVector) x).getDataWithoutCopying();
-        } else if (x instanceof Byte) {
-            return new byte[]{(Byte) x};
-        } else {
-            throw unimplemented();
+        if (tracing) {
+            RFFIUtils.traceUpCall("LOGICAL", x);
         }
+        return delegate.LOGICAL(x);
     }
 
     @Override
     public Object INTEGER(Object x) {
-        if (tracer != null) {
-            tracer.INTEGER(x);
-        }
-        if (x instanceof RIntVector) {
-            return ((RIntVector) x).getDataWithoutCopying();
-        } else if (x instanceof RIntSequence) {
-            return ((RIntSequence) x).materialize().getDataWithoutCopying();
-        } else if (x instanceof Integer) {
-            return new int[]{(Integer) x};
-        } else if (x instanceof RLogicalVector) {
-            RLogicalVector vec = (RLogicalVector) x;
-            int[] result = new int[vec.getLength()];
-            for (int i = 0; i < result.length; i++) {
-                result[i] = vec.getDataAt(i);
-            }
-            return result;
-        } else {
-            guaranteeInstanceOf(x, Byte.class);
-            return new int[]{(Byte) x};
+        if (tracing) {
+            RFFIUtils.traceUpCall("INTEGER", x);
         }
+        return delegate.INTEGER(x);
     }
 
     @Override
     public Object REAL(Object x) {
-        if (tracer != null) {
-            tracer.REAL(x);
-        }
-        if (x instanceof RDoubleVector) {
-            return ((RDoubleVector) x).getDataWithoutCopying();
-        } else if (x instanceof RDoubleSequence) {
-            return ((RDoubleSequence) x).materialize().getDataWithoutCopying();
-        } else {
-            guaranteeInstanceOf(x, Double.class);
-            return new double[]{(Double) x};
+        if (tracing) {
+            RFFIUtils.traceUpCall("REAL", x);
         }
+        return delegate.REAL(x);
     }
 
     @Override
     public Object STRING_ELT(Object x, int i) {
-        if (tracer != null) {
-            tracer.STRING_ELT(x, i);
+        if (tracing) {
+            RFFIUtils.traceUpCall("STRING_ELT", x, i);
         }
-        RAbstractStringVector vector = guaranteeInstanceOf(RRuntime.asAbstractVector(x), RAbstractStringVector.class);
-        return CharSXPWrapper.create(vector.getDataAt(i));
+        return delegate.STRING_ELT(x, i);
     }
 
     @Override
     public Object VECTOR_ELT(Object x, int i) {
-        if (tracer != null) {
-            tracer.VECTOR_ELT(x, i);
-        }
-        Object vec = x;
-        if (vec instanceof RExpression) {
-            return ((RExpression) vec).getDataAt(i);
+        if (tracing) {
+            RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
         }
-        RAbstractListVector list = guaranteeInstanceOf(RRuntime.asAbstractVector(vec), RAbstractListVector.class);
-        return list.getDataAt(i);
+        return delegate.VECTOR_ELT(x, i);
     }
 
     @Override
     public int NAMED(Object x) {
-        if (tracer != null) {
-            tracer.NAMED(x);
-        }
-        if (x instanceof RShareable) {
-            return ((RShareable) x).isShared() ? 1 : 0;
-        } else {
-            throw unimplemented();
+        if (tracing) {
+            RFFIUtils.traceUpCall("NAMED", x);
         }
+        return delegate.NAMED(x);
     }
 
     @Override
     public Object SET_TYPEOF_FASTR(Object x, int v) {
-        if (tracer != null) {
-            tracer.SET_TYPEOF_FASTR(x, v);
-        }
-        int code = SEXPTYPE.gnuRCodeForObject(x);
-        if (code == SEXPTYPE.LISTSXP.code && v == SEXPTYPE.LANGSXP.code) {
-            return RLanguage.fromList(x, RLanguage.RepType.CALL);
-        } else {
-            throw unimplemented();
+        if (tracing) {
+            RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
         }
+        return delegate.SET_TYPEOF_FASTR(x, v);
     }
 
     @Override
     public int TYPEOF(Object x) {
-        if (tracer != null) {
-            tracer.TYPEOF(x);
-        }
-        if (x instanceof CharSXPWrapper) {
-            return SEXPTYPE.CHARSXP.code;
-        } else {
-            return SEXPTYPE.gnuRCodeForObject(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("TYPEOF", x);
         }
+        return delegate.TYPEOF(x);
     }
 
     @Override
-    @TruffleBoundary
     public int OBJECT(Object x) {
-        if (tracer != null) {
-            tracer.OBJECT(x);
-        }
-        if (x instanceof RAttributable) {
-            return ((RAttributable) x).getAttr(RRuntime.CLASS_ATTR_KEY) == null ? 0 : 1;
-        } else {
-            return 0;
+        if (tracing) {
+            RFFIUtils.traceUpCall("OBJECT", x);
         }
+        return delegate.OBJECT(x);
     }
 
     @Override
     public Object Rf_duplicate(Object x, int deep) {
-        if (tracer != null) {
-            tracer.Rf_duplicate(x, deep);
-        }
-        guarantee(x != null, "unexpected type: null instead of " + x.getClass().getSimpleName());
-        guarantee(x instanceof RShareable || x instanceof RSequence || x instanceof RExternalPtr,
-                        "unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of RShareable or RExternalPtr");
-        if (x instanceof RShareable) {
-            return deep == 1 ? ((RShareable) x).deepCopy() : ((RShareable) x).copy();
-        } else if (x instanceof RSequence) {
-            return ((RSequence) x).materializeToShareable();
-        } else {
-            return ((RExternalPtr) x).copy();
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_duplicate", x, deep);
         }
+        return delegate.Rf_duplicate(x, deep);
     }
 
     @Override
     public int Rf_anyDuplicated(Object x, int fromLast) {
-        if (tracer != null) {
-            tracer.Rf_anyDuplicated(x, fromLast);
-        }
-        RAbstractVector vec = (RAbstractVector) x;
-        if (vec.getLength() == 0) {
-            return 0;
-        } else {
-            return DuplicationHelper.analyze(vec, null, true, fromLast != 0).getIndex();
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
         }
+        return delegate.Rf_anyDuplicated(x, fromLast);
     }
 
     @Override
     public Object PRINTNAME(Object x) {
-        if (tracer != null) {
-            tracer.PRINTNAME(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("PRINTNAME", x);
         }
-        guaranteeInstanceOf(x, RSymbol.class);
-        return CharSXPWrapper.create(((RSymbol) x).getName());
+        return delegate.PRINTNAME(x);
     }
 
     @Override
     public Object TAG(Object e) {
-        if (tracer != null) {
-            tracer.TAG(e);
-        }
-        if (e instanceof RPairList) {
-            return ((RPairList) e).getTag();
-        } else {
-            guaranteeInstanceOf(e, RExternalPtr.class);
-            // at the moment, this can only be used to null out the pointer
-            return ((RExternalPtr) e).getTag();
+        if (tracing) {
+            RFFIUtils.traceUpCall("TAG", e);
         }
+        return delegate.TAG(e);
     }
 
     @Override
     public Object CAR(Object e) {
-        if (tracer != null) {
-            tracer.CAR(e);
+        if (tracing) {
+            RFFIUtils.traceUpCall("CAR", e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CAR).call(e);
+        return delegate.CAR(e);
     }
 
     @Override
     public Object CDR(Object e) {
-        if (tracer != null) {
-            tracer.CDR(e);
+        if (tracing) {
+            RFFIUtils.traceUpCall("CDR", e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CDR).call(e);
+        return delegate.CDR(e);
     }
 
     @Override
     public Object CADR(Object e) {
-        if (tracer != null) {
-            tracer.CADR(e);
+        if (tracing) {
+            RFFIUtils.traceUpCall("CADR", e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CADR).call(e);
+        return delegate.CADR(e);
     }
 
     @Override
     public Object CADDR(Object e) {
-        if (tracer != null) {
-            tracer.CADDR(e);
+        if (tracing) {
+            RFFIUtils.traceUpCall("CADDR", e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CADDR).call(e);
+        return delegate.CADDR(e);
     }
 
     @Override
     public Object CDDR(Object e) {
-        if (tracer != null) {
-            tracer.CDDR(e);
+        if (tracing) {
+            RFFIUtils.traceUpCall("CDDR", e);
         }
-        return FFIUpCallRootNode.getCallTarget(UpCallsIndex.CDDR).call(e);
+        return delegate.CDDR(e);
     }
 
     @Override
     public Object SET_TAG(Object x, Object y) {
-        if (tracer != null) {
-            tracer.SET_TAG(x, y);
-        }
-        if (x instanceof RPairList) {
-            ((RPairList) x).setTag(y);
-        } else {
-            guaranteeInstanceOf(x, RExternalPtr.class);
-            // at the moment, this can only be used to null out the pointer
-            ((RExternalPtr) x).setTag(y);
+        if (tracing) {
+            RFFIUtils.traceUpCall("SET_TAG", x, y);
         }
-        return y;
+        return delegate.SET_TAG(x, y);
     }
 
     @Override
     public Object SETCAR(Object x, Object y) {
-        if (tracer != null) {
-            tracer.SETCAR(x, y);
+        if (tracing) {
+            RFFIUtils.traceUpCall("SETCAR", x, y);
         }
-        guaranteeInstanceOf(x, RPairList.class);
-        ((RPairList) x).setCar(y);
-        return y;
+        return delegate.SETCAR(x, y);
     }
 
     @Override
     public Object SETCDR(Object x, Object y) {
-        if (tracer != null) {
-            tracer.SETCDR(x, y);
+        if (tracing) {
+            RFFIUtils.traceUpCall("SETCDR", x, y);
         }
-        guaranteeInstanceOf(x, RPairList.class);
-        ((RPairList) x).setCdr(y);
-        return y;
+        return delegate.SETCDR(x, y);
     }
 
     @Override
     public Object SETCADR(Object x, Object y) {
-        if (tracer != null) {
-            tracer.SETCADR(x, y);
+        if (tracing) {
+            RFFIUtils.traceUpCall("SETCADR", x);
         }
-        SETCAR(CDR(x), y);
-        return y;
+        return delegate.SETCADR(x, y);
     }
 
     @Override
     public Object SYMVALUE(Object x) {
-        if (tracer != null) {
-            tracer.SYMVALUE(x);
-        }
-        if (!(x instanceof RSymbol)) {
-            throw RInternalError.shouldNotReachHere();
-        }
-        Object res = REnvironment.baseEnv().get(((RSymbol) x).getName());
-        if (res == null) {
-            return RUnboundValue.instance;
-        } else {
-            return res;
+        if (tracing) {
+            RFFIUtils.traceUpCall("SYMVALUE", x);
         }
+        return delegate.SYMVALUE(x);
     }
 
     @Override
     public void SET_SYMVALUE(Object x, Object v) {
-        if (tracer != null) {
-            tracer.SET_SYMVALUE(x, v);
-        }
-        if (!(x instanceof RSymbol)) {
-            throw RInternalError.shouldNotReachHere();
+        if (tracing) {
+            RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
         }
-        REnvironment.baseEnv().safePut(((RSymbol) x).getName(), v);
+        delegate.SET_SYMVALUE(x, v);
     }
 
     @Override
     public int R_BindingIsLocked(Object sym, Object env) {
-        if (tracer != null) {
-            tracer.R_BindingIsLocked(sym, env);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_BindingIsLocked", sym, env);
         }
-        guaranteeInstanceOf(sym, RSymbol.class);
-        guaranteeInstanceOf(env, REnvironment.class);
-        return ((REnvironment) env).bindingIsLocked(((RSymbol) sym).getName()) ? 1 : 0;
+        return delegate.R_BindingIsLocked(sym, env);
     }
 
     @Override
     public Object R_FindNamespace(Object name) {
-        if (tracer != null) {
-            tracer.R_FindNamespace(name);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_FindNamespace", name);
         }
-        Object result = RContext.getInstance().stateREnvironment.getNamespaceRegistry().get(RRuntime.asString(name));
-        return result;
+        return delegate.R_FindNamespace(name);
     }
 
     @Override
     public Object Rf_eval(Object expr, Object env) {
-        if (tracer != null) {
-            tracer.Rf_eval(expr, env);
-        }
-        guarantee(env instanceof REnvironment);
-        Object result;
-        if (expr instanceof RPromise) {
-            result = RContext.getRRuntimeASTAccess().forcePromise(null, expr);
-        } else if (expr instanceof RExpression) {
-            result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, RCaller.topLevel);
-        } else if (expr instanceof RLanguage) {
-            result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, RCaller.topLevel);
-        } else if (expr instanceof RPairList) {
-            RPairList l = (RPairList) expr;
-            RFunction f = (RFunction) l.car();
-            Object args = l.cdr();
-            if (args == RNull.instance) {
-                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, null, new Object[0]);
-            } else {
-                RList argsList = ((RPairList) args).toRList();
-                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, argsList.getNames(),
-                                argsList.getDataNonShared());
-            }
-        } else {
-            // just return value
-            result = expr;
-        }
-        return result;
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_eval", expr, env);
+        }
+        return delegate.Rf_eval(expr, env);
     }
 
     @Override
     public Object Rf_findfun(Object symbolObj, Object envObj) {
-        if (tracer != null) {
-            tracer.Rf_findfun(symbolObj, envObj);
-        }
-        guarantee(envObj instanceof REnvironment);
-        REnvironment env = (REnvironment) envObj;
-        guarantee(symbolObj instanceof RSymbol);
-        RSymbol symbol = (RSymbol) symbolObj;
-        // Works but not remotely efficient
-        Source source = RSource.fromTextInternal("get(\"" + symbol.getName() + "\", mode=\"function\")", RSource.Internal.RF_FINDFUN);
-        try {
-            Object result = RContext.getEngine().parseAndEval(source, env.getFrame(), false);
-            return result;
-        } catch (ParseException ex) {
-            throw RInternalError.shouldNotReachHere(ex);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
         }
+        return delegate.Rf_findfun(symbolObj, envObj);
     }
 
     @Override
     public Object Rf_GetOption1(Object tag) {
-        if (tracer != null) {
-            tracer.Rf_GetOption1(tag);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_GetOption1", tag);
         }
-        guarantee(tag instanceof RSymbol);
-        Object result = RContext.getInstance().stateROptions.getValue(((RSymbol) tag).getName());
-        return result;
+        return delegate.Rf_GetOption1(tag);
     }
 
     @Override
     public void Rf_gsetVar(Object symbol, Object value, Object rho) {
-        if (tracer != null) {
-            tracer.Rf_gsetVar(symbol, value, rho);
-        }
-        guarantee(symbol instanceof RSymbol);
-        REnvironment baseEnv = RContext.getInstance().stateREnvironment.getBaseEnv();
-        guarantee(rho == baseEnv);
-        try {
-            baseEnv.put(((RSymbol) symbol).getName(), value);
-        } catch (PutException e) {
-            e.printStackTrace();
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
         }
+        delegate.Rf_gsetVar(symbol, value, rho);
     }
 
     @Override
     public void DUPLICATE_ATTRIB(Object to, Object from) {
-        if (tracer != null) {
-            tracer.DUPLICATE_ATTRIB(to, from);
+        if (tracing) {
+            RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
         }
-        if (from instanceof RAttributable) {
-            guaranteeInstanceOf(to, RAttributable.class);
-            DynamicObject attributes = ((RAttributable) from).getAttributes();
-            ((RAttributable) to).initAttributes(attributes == null ? null : RAttributesLayout.copy(attributes));
-        }
-        // TODO: copy OBJECT? and S4 attributes
+        delegate.DUPLICATE_ATTRIB(to, from);
     }
 
     @Override
     public int R_computeIdentical(Object x, Object y, int flags) {
-        if (tracer != null) {
-            tracer.R_computeIdentical(x, y, flags);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
         }
-        RFunction indenticalBuiltin = RContext.lookupBuiltin("identical");
-        Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
-                        RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0))));
-        return (int) res;
+        return delegate.R_computeIdentical(x, y, flags);
     }
 
     @Override
     public void Rf_copyListMatrix(Object s, Object t, int byrow) {
-        if (tracer != null) {
-            tracer.Rf_copyListMatrix(s, t, byrow);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
         }
-        throw unimplemented();
+        delegate.Rf_copyListMatrix(s, t, byrow);
     }
 
     @Override
     public void Rf_copyMatrix(Object s, Object t, int byrow) {
-        if (tracer != null) {
-            tracer.Rf_copyMatrix(s, t, byrow);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
         }
-        throw unimplemented();
+        delegate.Rf_copyMatrix(s, t, byrow);
     }
 
     @Override
     public Object R_tryEval(Object expr, Object env, boolean silent) {
-        if (tracer != null) {
-            tracer.R_tryEval(expr, env, silent);
-        }
-        Object handlerStack = RErrorHandling.getHandlerStack();
-        Object restartStack = RErrorHandling.getRestartStack();
-        try {
-            // TODO handle silent
-            RErrorHandling.resetStacks();
-            Object result = Rf_eval(expr, env);
-            return result;
-        } catch (Throwable t) {
-            return null;
-        } finally {
-            RErrorHandling.restoreStacks(handlerStack, restartStack);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
         }
+        return delegate.R_tryEval(expr, env, silent);
     }
 
-    /**
-     * 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.
-     */
     @Override
     public Object R_ToplevelExec() {
-        if (tracer != null) {
-            tracer.R_ToplevelExec();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_TopLevelExec");
         }
-        return RErrorHandling.resetAndGetHandlerStacks();
-    }
-
-    /**
-     * Helper function for {@code R_TopLevelExec}, see {@link #R_ToplevelExec()}, called after C
-     * function returns.
-     */
-    public void R_ToplevelExecRestoreErrorHandlerStacks(Object stacks) {
-        RErrorHandling.HandlerStacks handlerStacks = guaranteeInstanceOf(stacks, RErrorHandling.HandlerStacks.class);
-        RErrorHandling.restoreHandlerStacks(handlerStacks);
+        return delegate.R_ToplevelExec();
     }
 
     @Override
     public int RDEBUG(Object x) {
-        if (tracer != null) {
-            tracer.RDEBUG(x);
-        }
-        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
-        if (env instanceof REnvironment.Function) {
-            REnvironment.Function funcEnv = (REnvironment.Function) env;
-            RFunction func = RArguments.getFunction(funcEnv.getFrame());
-            return RContext.getRRuntimeASTAccess().isDebugged(func) ? 1 : 0;
-        } else {
-            return 0;
+        if (tracing) {
+            RFFIUtils.traceUpCall("RDEBUG", x);
         }
+        return delegate.RDEBUG(x);
     }
 
     @Override
     public void SET_RDEBUG(Object x, int v) {
-        if (tracer != null) {
-            tracer.SET_RDEBUG(x, v);
-        }
-        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
-        if (env instanceof REnvironment.Function) {
-            REnvironment.Function funcEnv = (REnvironment.Function) env;
-            RFunction func = RArguments.getFunction(funcEnv.getFrame());
-            if (v == 1) {
-                RContext.getRRuntimeASTAccess().enableDebug(func, false);
-            } else {
-                RContext.getRRuntimeASTAccess().disableDebug(func);
-            }
+        if (tracing) {
+            RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
         }
+        delegate.SET_RDEBUG(x, v);
     }
 
     @Override
     public int RSTEP(Object x) {
-        if (tracer != null) {
-            tracer.RSTEP(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("RSTEP", x);
         }
-        @SuppressWarnings("unused")
-        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
-        throw RInternalError.unimplemented("RSTEP");
+        return delegate.RSTEP(x);
     }
 
     @Override
     public void SET_RSTEP(Object x, int v) {
-        if (tracer != null) {
-            tracer.SET_RSTEP(x, v);
+        if (tracing) {
+            RFFIUtils.traceUpCall("SET_RSTEP", x, v);
         }
-        @SuppressWarnings("unused")
-        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
-        throw RInternalError.unimplemented("SET_RSTEP");
+        delegate.SET_RSTEP(x, v);
     }
 
     @Override
     public Object ENCLOS(Object x) {
-        if (tracer != null) {
-            tracer.ENCLOS(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("ENCLOS", x);
         }
-        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
-        Object result = env.getParent();
-        if (result == null) {
-            result = RNull.instance;
-        }
-        return result;
+        return delegate.ENCLOS(x);
     }
 
     @Override
     public Object PRVALUE(Object x) {
-        if (tracer != null) {
-            tracer.PRVALUE(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("PRVALUE", x);
         }
-        RPromise p = guaranteeInstanceOf(x, RPromise.class);
-        return p.isEvaluated() ? p.getValue() : RUnboundValue.instance;
+        return delegate.PRVALUE(x);
     }
 
     @Override
     public Object R_ParseVector(Object text, int n, Object srcFile) {
-        if (tracer != null) {
-            tracer.R_ParseVector(text, n, srcFile);
-        }
-        // TODO general case
-        assert n == 1;
-        assert srcFile == RNull.instance;
-        String textString = RRuntime.asString(text);
-        assert textString != null;
-
-        try {
-            Source source = RSource.fromTextInternal(textString, RSource.Internal.R_PARSEVECTOR);
-            RExpression exprs = RContext.getEngine().parse(source);
-            return new ParseResult(ParseStatus.PARSE_OK.ordinal(), exprs);
-        } catch (ParseException ex) {
-            // TODO incomplete
-            return new ParseResult(ParseStatus.PARSE_ERROR.ordinal(), RNull.instance);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_ParseVector", text, n, srcFile);
         }
+        return delegate.R_ParseVector(text, n, srcFile);
     }
 
     @Override
     public Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
-        if (tracer != null) {
-            tracer.R_lsInternal3(envArg, allArg, sortedArg);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_lsInternal3", envArg, allArg, sortedArg);
         }
-        boolean sorted = sortedArg != 0;
-        boolean all = allArg != 0;
-        REnvironment env = guaranteeInstanceOf(envArg, REnvironment.class);
-        return env.ls(all, null, sorted);
+        return delegate.R_lsInternal3(envArg, allArg, sortedArg);
     }
 
     @Override
     public String R_HomeDir() {
-        if (tracer != null) {
-            tracer.R_HomeDir();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_HomeDir");
         }
-        return REnvVars.rHome();
+        return delegate.R_HomeDir();
     }
 
     @Override
     public void R_CleanUp(int sa, int status, int runlast) {
-        if (tracer != null) {
-            tracer.R_CleanUp(sa, status, runlast);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_Cleanup", sa, status, runlast);
         }
-        RCleanUp.stdCleanUp(SA_TYPE.values()[sa], status, runlast != 0);
+        delegate.R_CleanUp(sa, status, runlast);
     }
 
     @Override
     public Object R_GlobalContext() {
-        if (tracer != null) {
-            tracer.R_GlobalContext();
-        }
-        Utils.warn("Potential memory leak (global context object)");
-        Frame frame = Utils.getActualCurrentFrame();
-        if (frame == null) {
-            return RCaller.topLevel;
-        }
-        if (RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser()) {
-            return RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_GlobalContext");
         }
-        RCaller rCaller = RArguments.getCall(frame);
-        return rCaller == null ? RCaller.topLevel : rCaller;
+        return delegate.R_GlobalContext();
     }
 
     @Override
     public Object R_GlobalEnv() {
-        if (tracer != null) {
-            tracer.R_GlobalEnv();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_GlobalEnv");
         }
-        return RContext.getInstance().stateREnvironment.getGlobalEnv();
+        return delegate.R_GlobalEnv();
     }
 
     @Override
     public Object R_BaseEnv() {
-        if (tracer != null) {
-            tracer.R_BaseEnv();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_BaseEnv");
         }
-        return RContext.getInstance().stateREnvironment.getBaseEnv();
+        return delegate.R_BaseEnv();
     }
 
     @Override
     public Object R_BaseNamespace() {
-        if (tracer != null) {
-            tracer.R_BaseNamespace();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_BaseNamespace");
         }
-        return RContext.getInstance().stateREnvironment.getBaseNamespace();
+        return delegate.R_BaseNamespace();
     }
 
     @Override
     public Object R_NamespaceRegistry() {
-        if (tracer != null) {
-            tracer.R_NamespaceRegistry();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_NamespaceRegistry");
         }
-        return RContext.getInstance().stateREnvironment.getNamespaceRegistry();
+        return delegate.R_NamespaceRegistry();
     }
 
     @Override
     public int R_Interactive() {
-        if (tracer != null) {
-            tracer.R_Interactive();
+        if (tracing) {
+            RFFIUtils.traceUpCall("isInteractive");
         }
-        return RContext.getInstance().isInteractive() ? 1 : 0;
+        return delegate.R_Interactive();
     }
 
     @Override
     public int IS_S4_OBJECT(Object x) {
-        if (tracer != null) {
-            tracer.IS_S4_OBJECT(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("isS4Object");
         }
-        return x instanceof RS4Object ? 1 : 0;
+        return delegate.IS_S4_OBJECT(x);
     }
 
     @Override
-    public void Rprintf(String message) {
-        if (tracer != null) {
-            tracer.Rprintf(message);
+    public void Rprintf(Object message) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rprintf", message);
         }
-        RContext.getInstance().getConsoleHandler().print(message);
+        delegate.Rprintf(message);
     }
 
     @Override
     public void GetRNGstate() {
-        if (tracer != null) {
-            tracer.GetRNGstate();
+        if (tracing) {
+            RFFIUtils.traceUpCall("GetRNGstate");
         }
-        RRNG.getRNGState();
+        delegate.GetRNGstate();
     }
 
     @Override
     public void PutRNGstate() {
-        if (tracer != null) {
-            tracer.PutRNGstate();
+        if (tracing) {
+            RFFIUtils.traceUpCall("PutRNGstate");
         }
-        RRNG.putRNGState();
+        delegate.PutRNGstate();
     }
 
     @Override
     public double unif_rand() {
-        if (tracer != null) {
-            tracer.unif_rand();
+        if (tracing) {
+            RFFIUtils.traceUpCall("unif_rand");
         }
-        return RRNG.unifRand();
+        return delegate.unif_rand();
     }
 
-    // Checkstyle: stop method name check
-
     @Override
     public Object R_getGlobalFunctionContext() {
-        if (tracer != null) {
-            tracer.R_getGlobalFunctionContext();
-        }
-        Utils.warn("Potential memory leak (global function context object)");
-        Frame frame = Utils.getActualCurrentFrame();
-        if (frame == null) {
-            return RNull.instance;
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_getGlobalFunctionContext");
         }
-        RCaller currentCaller = RArguments.getCall(frame);
-        while (currentCaller != null) {
-            if (!currentCaller.isPromise() && currentCaller.isValidCaller() && currentCaller != RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller()) {
-                break;
-            }
-            currentCaller = currentCaller.getParent();
-        }
-        return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller;
+        return delegate.R_getGlobalFunctionContext();
     }
 
     @Override
     public Object R_getParentFunctionContext(Object c) {
-        if (tracer != null) {
-            tracer.R_getParentFunctionContext(c);
-        }
-        Utils.warn("Potential memory leak (parent function context object)");
-        RCaller currentCaller = guaranteeInstanceOf(c, RCaller.class);
-        while (true) {
-            currentCaller = currentCaller.getParent();
-            if (currentCaller == null ||
-                            (!currentCaller.isPromise() && currentCaller.isValidCaller() && currentCaller != RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller())) {
-                break;
-            }
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_getParentFunctionContext");
         }
-        return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller;
+        return delegate.R_getParentFunctionContext(c);
     }
 
     @Override
     public Object R_getContextEnv(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextEnv(c);
-        }
-        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
-        if (rCaller == RCaller.topLevel) {
-            return RContext.getInstance().stateREnvironment.getGlobalEnv();
-        }
-        Frame frame = Utils.getActualCurrentFrame();
-        if (RArguments.getCall(frame) == rCaller) {
-            return REnvironment.frameToEnvironment(frame.materialize());
-        } else {
-            Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
-
-                @Override
-                public Object apply(Frame f) {
-                    RCaller currentCaller = RArguments.getCall(f);
-                    if (currentCaller == rCaller) {
-                        return REnvironment.frameToEnvironment(f.materialize());
-                    } else {
-                        return null;
-                    }
-                }
-            });
-            return result;
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_getContextEnv", c);
         }
+        return delegate.R_getContextEnv(c);
     }
 
     @Override
     public Object R_getContextFun(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextFun(c);
-        }
-        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
-        if (rCaller == RCaller.topLevel) {
-            return RNull.instance;
-        }
-        Frame frame = Utils.getActualCurrentFrame();
-        if (RArguments.getCall(frame) == rCaller) {
-            return RArguments.getFunction(frame);
-        } else {
-            Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
-
-                @Override
-                public Object apply(Frame f) {
-                    RCaller currentCaller = RArguments.getCall(f);
-                    if (currentCaller == rCaller) {
-                        return RArguments.getFunction(f);
-                    } else {
-                        return null;
-                    }
-                }
-            });
-            return result;
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_getContextFun", c);
         }
+        return delegate.R_getContextFun(c);
     }
 
     @Override
     public Object R_getContextCall(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextCall(c);
-        }
-        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
-        if (rCaller == RCaller.topLevel) {
-            return RNull.instance;
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_getContextCall", c);
         }
-        return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller);
+        return delegate.R_getContextCall(c);
     }
 
     @Override
     public Object R_getContextSrcRef(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextSrcRef(c);
-        }
-        Object o = R_getContextFun(c);
-        if (!(o instanceof RFunction)) {
-            return RNull.instance;
-        } else {
-            RFunction f = (RFunction) o;
-            SourceSection ss = f.getRootNode().getSourceSection();
-            String path = RSource.getPath(ss.getSource());
-            // TODO: is it OK to pass "" if path is null?
-            return RSrcref.createLloc(ss, path == null ? "" : path);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_getContextSrcRef", c);
         }
+        return delegate.R_getContextSrcRef(c);
     }
 
     @Override
     public int R_insideBrowser() {
-        if (tracer != null) {
-            tracer.R_insideBrowser();
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_insideBrowser");
         }
-        return RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser() ? 1 : 0;
+        return delegate.R_insideBrowser();
     }
 
     @Override
     public int R_isGlobal(Object c) {
-        if (tracer != null) {
-            tracer.R_isGlobal(c);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_isGlobal", c);
         }
-        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
-
-        return rCaller == RCaller.topLevel ? 1 : 0;
+        return delegate.R_isGlobal(c);
     }
 
     @Override
     public int R_isEqual(Object x, Object y) {
-        if (tracer != null) {
-            tracer.R_isEqual(x, y);
+        if (tracing) {
+            RFFIUtils.traceUpCall("isEqual", x, y);
         }
-        return x == y ? 1 : 0;
+        return delegate.R_isEqual(x, y);
     }
 
     @Override
-    @TruffleBoundary
     public Object Rf_classgets(Object x, Object y) {
-        if (tracer != null) {
-            tracer.Rf_classgets(x, y);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_classgets", x, y);
         }
-        RAbstractVector vector = guaranteeInstanceOf(x, RAbstractVector.class);
-        vector.setClassAttr(guaranteeInstanceOf(y, RStringVector.class));
-        return RNull.instance;
+        return delegate.Rf_classgets(x, y);
     }
 
     @Override
     public RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
-        if (tracer != null) {
-            tracer.R_MakeExternalPtr(addr, tag, prot);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_MakeExternalPtr", addr, tag, prot);
         }
-        return RDataFactory.createExternalPtr(new SymbolHandle(addr), tag, prot);
+        return delegate.R_MakeExternalPtr(addr, tag, prot);
     }
 
     @Override
     public long R_ExternalPtrAddr(Object x) {
-        if (tracer != null) {
-            tracer.R_ExternalPtrAddr(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_ExternalPtrAddr", x);
         }
-        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
-        return p.getAddr().asAddress();
+        return delegate.R_ExternalPtrAddr(x);
     }
 
     @Override
     public Object R_ExternalPtrTag(Object x) {
-        if (tracer != null) {
-            tracer.R_ExternalPtrTag(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_ExternalPtrTag", x);
         }
-        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
-        return p.getTag();
+        return delegate.R_ExternalPtrTag(x);
     }
 
     @Override
     public Object R_ExternalPtrProt(Object x) {
-        if (tracer != null) {
-            tracer.R_ExternalPtrProt(x);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
         }
-        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
-        return p.getProt();
+        return delegate.R_ExternalPtrProt(x);
     }
 
     @Override
     public void R_SetExternalPtrAddr(Object x, long addr) {
-        if (tracer != null) {
-            tracer.R_SetExternalPtrAddr(x, addr);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_SetExternalPtrAddr", x);
         }
-        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
-        p.setAddr(new SymbolHandle(addr));
+        delegate.R_SetExternalPtrAddr(x, addr);
     }
 
     @Override
     public void R_SetExternalPtrTag(Object x, Object tag) {
-        if (tracer != null) {
-            tracer.R_SetExternalPtrTag(x, tag);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_SetExternalPtrTag", x);
         }
-        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
-        p.setTag(tag);
+        delegate.R_SetExternalPtrTag(x, tag);
     }
 
     @Override
     public void R_SetExternalPtrProt(Object x, Object prot) {
-        if (tracer != null) {
-            tracer.R_SetExternalPtrProt(x, prot);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
         }
-        RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
-        p.setProt(prot);
+        delegate.R_SetExternalPtrProt(x, prot);
     }
 
     @Override
-    public REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
-        if (tracer != null) {
-            tracer.R_NewHashedEnv(parent, name, hashed, initialSize);
+    public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) {
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, initialSize);
         }
-        REnvironment env = RDataFactory.createNewEnv(name, hashed, initialSize);
-        RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
-        return env;
+        return delegate.R_NewHashedEnv(parent, initialSize);
     }
 
     // Implementation specific support
 
+    /**
+     * Helper function for {@code R_TopLevelExec}, see {@link #R_ToplevelExec()}, called after C
+     * function returns.
+     */
+    @SuppressWarnings("static-method")
+    public void R_ToplevelExecRestoreErrorHandlerStacks(Object stacks) {
+        RErrorHandling.HandlerStacks handlerStacks = guaranteeInstanceOf(stacks, RErrorHandling.HandlerStacks.class);
+        RErrorHandling.restoreHandlerStacks(handlerStacks);
+    }
+
     /**
      * Called to possibly update the "complete" status on {@code x}. N.B. {@code x} may not be an
      * object with a concrete {@code setComplete} method, e.g. see {@link #INTEGER(Object)}.
      */
+    @SuppressWarnings("static-method")
     public void setComplete(Object x, boolean complete) {
         // only care about concrete vectors
         if (x instanceof RVector) {
@@ -1506,6 +954,7 @@ public class UpCallsRFFIImpl implements UpCallsRFFI {
     /**
      * Called when a {@link CharSXPWrapper} is expected and not found.
      */
+    @SuppressWarnings("static-method")
     public void logNotCharSXPWrapper(Object x) {
         System.out.println("object " + x);
         System.out.println("class " + x.getClass());
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
index d7154d5a2cdd42a3f668d7cceb8a4b398a60dadd..b766682261eb2c0da7e604ac025fdb10927dff39 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
@@ -27,8 +27,9 @@ import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceDownCallReturn;
 import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceEnabled;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.r.nodes.ffi.UpCallsRFFIImpl;
+import com.oracle.truffle.r.nodes.ffi.JavaUpCallsRFFIImpl;
 import com.oracle.truffle.r.nodes.ffi.RFFIUtils;
+import com.oracle.truffle.r.nodes.ffi.UpCallsRFFIImpl;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
@@ -128,7 +129,7 @@ public class JNI_Call implements CallRFFI {
             traceDownCall("initialize");
         }
         try {
-            initialize(new UpCallsRFFIImpl(), RFFIVariables.initialize());
+            initialize(new UpCallsRFFIImpl(new JavaUpCallsRFFIImpl()), RFFIVariables.initialize());
         } finally {
             if (traceEnabled()) {
                 traceDownCallReturn("initialize", null);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8dbee39e12f83ea246b81d120268560bb150ae7
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, 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.runtime.ffi;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Tags an upcall argument as being (on the native side) a C string.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+public @interface RFFICstring {
+
+}
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..b8f0ecf89d961d276e182a8fdb62576e4a77a304 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(@RFFICstring 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(@RFFICstring 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(@RFFICstring Object x, Object clazz);
 
-    Object Rf_install(String name);
+    Object Rf_install(@RFFICstring 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(@RFFICstring Object msg);
 
-    void Rf_warning(String msg);
+    void Rf_warning(@RFFICstring Object msg);
 
-    void Rf_warningcall(Object call, String msg);
+    void Rf_warningcall(Object call, @RFFICstring 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(@RFFICstring 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..60881ee7aa783cb76a6fd2a395922f92b7c708df
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java
@@ -0,0 +1,96 @@
+/*
+ * 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.annotation.Annotation;
+import java.lang.reflect.AnnotatedType;
+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.RFFICstring;
+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();
+        Annotation[][] annotations = m.getParameterAnnotations();
+        StringBuilder sb = new StringBuilder();
+        sb.append('(');
+        for (int i = 0; i < paramTypes.length; i++) {
+            Class<?> paramType = paramTypes[i];
+            String nfiParam = nfiParamName(paramType, annotations[i]);
+            sb.append(nfiParam);
+            if (i != paramTypes.length - 1) {
+                sb.append(", ");
+            }
+        }
+        sb.append(')');
+        sb.append(" : ");
+        sb.append(nfiParamName(m.getReturnType(), new Annotation[0]));
+        return sb.toString();
+    }
+
+    static String nfiParamName(Class<?> paramType, Annotation[] annotation) {
+        String paramName = paramType.getSimpleName();
+        Class<?> klass = annotation.length == 0 ? null : annotation[0].annotationType();
+        switch (paramName) {
+            case "Object":
+                return klass == null ? "object" : "pointer";
+            case "int":
+                return "sint32";
+            case "double":
+                return "double";
+            case "void":
+                return "void";
+            default:
+                return "object";
+        }
+
+    }
+
+}