diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index f004349cc8abf9fbaeb4f8a6c510b8b3f742de6d..f31134fbfb5118c45a0cddb826da36f2d9e6bcb1 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -43,8 +43,6 @@ 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.ffi.impl.common.ParseResult.ParseStatus;
-import com.oracle.truffle.r.ffi.impl.nodes.FFIUpCallRootNode;
-import com.oracle.truffle.r.ffi.impl.upcalls.RFFIUpCallTable;
 import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
@@ -130,6 +128,10 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     private final Map<String, Object> nameSymbolCache = new ConcurrentHashMap<>();
 
+    private static RuntimeException implementedAsNode() {
+        throw RInternalError.shouldNotReachHere("upcall function is implemented via a node");
+    }
+
     // Checkstyle: stop method name check
 
     @Override
@@ -161,27 +163,27 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public int Rf_asInteger(Object x) {
-        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_asInteger).call(x);
+        throw implementedAsNode();
     }
 
     @Override
     public double Rf_asReal(Object x) {
-        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_asReal).call(x);
+        throw implementedAsNode();
     }
 
     @Override
     public int Rf_asLogical(Object x) {
-        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_asLogical).call(x);
+        throw implementedAsNode();
     }
 
     @Override
     public Object Rf_asChar(Object x) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_asChar).call(x);
+        throw implementedAsNode();
     }
 
     @Override
     public Object Rf_coerceVector(Object x, int mode) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_coerceVector).call(x, mode);
+        throw implementedAsNode();
     }
 
     @Override
@@ -216,7 +218,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public Object R_do_new_object(Object classDef) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.R_do_new_object).call(classDef);
+        throw implementedAsNode();
     }
 
     @Override
@@ -261,10 +263,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public Object ATTRIB(Object obj) {
-        if (obj instanceof RAttributable) {
-            return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.ATTRIB).call(obj);
-        }
-        return RNull.instance;
+        throw implementedAsNode();
     }
 
     @Override
@@ -488,7 +487,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public int LENGTH(Object x) {
-        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.LENGTH).call(x);
+        throw implementedAsNode();
     }
 
     @Override
@@ -687,28 +686,27 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public Object CAR(Object e) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.CAR).call(e);
+        throw implementedAsNode();
     }
 
     @Override
     public Object CDR(Object e) {
-        Object result = FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.CDR).call(e);
-        return result;
+        throw implementedAsNode();
     }
 
     @Override
     public Object CADR(Object e) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.CADR).call(e);
+        throw implementedAsNode();
     }
 
     @Override
     public Object CADDR(Object e) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.CADDR).call(e);
+        throw implementedAsNode();
     }
 
     @Override
     public Object CDDR(Object e) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.CDDR).call(e);
+        throw implementedAsNode();
     }
 
     @Override
@@ -1510,12 +1508,12 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public Object R_do_slot(Object o, Object name) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.R_do_slot).call(o, name);
+        throw implementedAsNode();
     }
 
     @Override
     public Object R_do_slot_assign(Object o, Object name, Object value) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.R_do_slot_assign).call(o, name, value);
+        throw implementedAsNode();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java
index 760388b62c206b1aad234f6834d43cd961e9d013..f70ecdd4b315ca6732d421585aa3fa1f6ec1165f 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java
@@ -26,10 +26,11 @@ import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.file.Path;
+import java.util.List;
 
 import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.r.ffi.impl.nodes.FFIUpCallRootNode;
-import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.Utils;
@@ -45,7 +46,6 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
  * Embedded mode requires special treatment. Experimentally the primary embedding app, RStudio, sets
  * a very constrained environment (i.e. does not propagate environment variables set in the shell
  * that launches RStudio.) and sets the cwd to "/", which is not writeable.
- *
  */
 public class RFFIUtils {
     /**
@@ -55,7 +55,7 @@ public class RFFIUtils {
     /**
      * Is set by initialization and caches whether we are tracing.
      */
-    private static boolean traceEnabled;
+    @CompilationFinal public static boolean traceEnabled;
 
     /**
      * Always trace to a file because stdout is problematic for embedded mode.
@@ -68,23 +68,15 @@ public class RFFIUtils {
     private static int depth;
 
     /**
-     * Handles the initialization of the RFFI downcalls/upcall implementation.
-     *
-     * @param upCallsRFFIImpl the concrete, implementation-specific variant of {@link UpCallsRFFI}.
-     * @return if tracing is enabled an instance of {@link TracingUpCallsRFFIImpl} that wraps
-     *         {@code upCallsRFFIImpl} else {@code upCallsRFFIImpl}.
+     * Handles the initialization of the RFFI downcalls/upcall tracing implementation.
      */
-    public static UpCallsRFFI initialize(UpCallsRFFI upCallsRFFIImpl) {
-        UpCallsRFFI returnUpCallsRFFIImpl = upCallsRFFIImpl;
+    public static void initializeTracing() {
         traceEnabled = alwaysTrace || FastROptions.TraceNativeCalls.getBooleanValue();
         if (traceEnabled) {
             if (traceStream == null) {
                 initTraceStream();
             }
-            returnUpCallsRFFIImpl = new TracingUpCallsRFFIImpl(upCallsRFFIImpl);
         }
-        FFIUpCallRootNode.register();
-        return returnUpCallsRFFIImpl;
     }
 
     private static void initTraceStream() {
@@ -129,18 +121,22 @@ public class RFFIUtils {
         }
     }
 
-    public static void traceUpCall(String name, Object... args) {
-        traceCall(CallMode.UP, name, depth, args);
+    @TruffleBoundary
+    public static void traceUpCall(String name, List<Object> args) {
+        traceCall(CallMode.UP, name, depth, args.toArray());
     }
 
+    @TruffleBoundary
     public static void traceUpCallReturn(String name, Object result) {
         traceCall(CallMode.UP_RETURN, name, depth, result);
     }
 
+    @TruffleBoundary
     public static void traceDownCall(String name, Object... args) {
         traceCall(CallMode.DOWN, name, ++depth, args);
     }
 
+    @TruffleBoundary
     public static void traceDownCallReturn(String name, Object result) {
         traceCall(CallMode.DOWN_RETURN, name, depth--, result);
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java
index d4287407b14c8166a7062551c212a8d296298b53..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java
@@ -1,899 +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.ffi.impl.common;
-
-import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
-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;
-
-final class TracingUpCallsRFFIImpl implements UpCallsRFFI {
-    // Checkstyle: stop method name check
-
-    private final UpCallsRFFI delegate;
-
-    public TracingUpCallsRFFIImpl(UpCallsRFFI delegate) {
-        this.delegate = delegate;
-    }
-
-    @Override
-    public RIntVector Rf_ScalarInteger(int value) {
-        RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
-        return delegate.Rf_ScalarInteger(value);
-    }
-
-    @Override
-    public RLogicalVector Rf_ScalarLogical(int value) {
-        RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
-        return delegate.Rf_ScalarLogical(value);
-    }
-
-    @Override
-    public RDoubleVector Rf_ScalarDouble(double value) {
-        RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
-        return delegate.Rf_ScalarDouble(value);
-    }
-
-    @Override
-    public RStringVector Rf_ScalarString(Object value) {
-        RFFIUtils.traceUpCall("Rf_ScalarString", value);
-        return delegate.Rf_ScalarString(value);
-    }
-
-    @Override
-    public int Rf_asInteger(Object x) {
-        RFFIUtils.traceUpCall("Rf_asInteger", x);
-        return delegate.Rf_asInteger(x);
-    }
-
-    @Override
-    public double Rf_asReal(Object x) {
-        RFFIUtils.traceUpCall("Rf_asReal", x);
-        return delegate.Rf_asReal(x);
-    }
-
-    @Override
-    public int Rf_asLogical(Object x) {
-        RFFIUtils.traceUpCall("Rf_asLogical", x);
-        return delegate.Rf_asLogical(x);
-    }
-
-    @Override
-    public Object Rf_asChar(Object x) {
-        RFFIUtils.traceUpCall("Rf_asChar", x);
-        return delegate.Rf_asChar(x);
-    }
-
-    @Override
-    public Object Rf_coerceVector(Object x, int mode) {
-        RFFIUtils.traceUpCall("Rf_coerceVector", x, mode);
-        return delegate.Rf_coerceVector(x, mode);
-    }
-
-    @Override
-    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
-        RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
-        return delegate.Rf_mkCharLenCE(bytes, len, encoding);
-    }
-
-    @Override
-    public Object Rf_cons(Object car, Object cdr) {
-        RFFIUtils.traceUpCall("Rf_cons", car, cdr);
-        return delegate.Rf_cons(car, cdr);
-    }
-
-    @Override
-    public int Rf_defineVar(Object symbolArg, Object value, Object envArg) {
-        RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
-        return delegate.Rf_defineVar(symbolArg, value, envArg);
-    }
-
-    @Override
-    public Object R_do_MAKE_CLASS(Object clazz) {
-        RFFIUtils.traceUpCall("R_do_MAKE_CLASS", clazz);
-        return delegate.R_do_MAKE_CLASS(clazz);
-    }
-
-    @Override
-    public Object R_do_new_object(Object classDef) {
-        RFFIUtils.traceUpCall("R_do_new_object", classDef);
-        return delegate.R_do_new_object(classDef);
-    }
-
-    @Override
-    public Object Rf_findVar(Object symbolArg, Object envArg) {
-        RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
-        return delegate.Rf_findVar(symbolArg, envArg);
-    }
-
-    @Override
-    public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
-        RFFIUtils.traceUpCall("Rf_findVarInFrame", envArg, symbolArg);
-        return delegate.Rf_findVarInFrame(envArg, symbolArg);
-    }
-
-    @Override
-    public Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet) {
-        RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
-        return delegate.Rf_findVarInFrame3(envArg, symbolArg, doGet);
-    }
-
-    @Override
-    public Object ATTRIB(Object obj) {
-        RFFIUtils.traceUpCall("ATTRIB");
-        return delegate.ATTRIB(obj);
-    }
-
-    @Override
-    public Object Rf_getAttrib(Object obj, Object name) {
-        RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
-        return delegate.Rf_getAttrib(obj, name);
-    }
-
-    @Override
-    public int Rf_setAttrib(Object obj, Object name, Object val) {
-        RFFIUtils.traceUpCall("Rf_setAttrib", obj, name, val);
-        return delegate.Rf_setAttrib(obj, name, val);
-    }
-
-    @Override
-    public int Rf_inherits(Object x, Object clazz) {
-        RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
-        return delegate.Rf_inherits(x, clazz);
-    }
-
-    @Override
-    public Object Rf_install(Object name) {
-        RFFIUtils.traceUpCall("Rf_install", name);
-        return delegate.Rf_install(name);
-    }
-
-    @Override
-    public Object Rf_installChar(Object name) {
-        RFFIUtils.traceUpCall("Rf_installChar", name);
-        return delegate.Rf_installChar(name);
-    }
-
-    @Override
-    public Object Rf_lengthgets(Object x, int newSize) {
-        RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
-        return delegate.Rf_lengthgets(x, newSize);
-    }
-
-    @Override
-    public int Rf_isString(Object x) {
-        RFFIUtils.traceUpCall("Rf_isString", x);
-        return delegate.Rf_isString(x);
-    }
-
-    @Override
-    public int Rf_isNull(Object x) {
-        RFFIUtils.traceUpCall("Rf_isNull", x);
-        return delegate.Rf_isNull(x);
-    }
-
-    @Override
-    public Object Rf_PairToVectorList(Object x) {
-        RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
-        return delegate.Rf_PairToVectorList(x);
-    }
-
-    @Override
-    public int Rf_error(Object msg) {
-        RFFIUtils.traceUpCall("Rf_error", msg);
-        return delegate.Rf_error(msg);
-    }
-
-    @Override
-    public int Rf_warning(Object msg) {
-        RFFIUtils.traceUpCall("Rf_warning", msg);
-        return delegate.Rf_warning(msg);
-    }
-
-    @Override
-    public int Rf_warningcall(Object call, Object msg) {
-        RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
-        return delegate.Rf_warningcall(call, msg);
-    }
-
-    @Override
-    public int Rf_errorcall(Object call, Object msg) {
-        RFFIUtils.traceUpCall("Rf_errorcall", call, msg);
-        return delegate.Rf_errorcall(call, msg);
-    }
-
-    @Override
-    public Object Rf_allocVector(int mode, long n) {
-        RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
-        return delegate.Rf_allocVector(mode, n);
-    }
-
-    @Override
-    public Object Rf_allocArray(int mode, Object dimsObj) {
-        RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
-        return null;
-    }
-
-    @Override
-    public Object Rf_allocMatrix(int mode, int nrow, int ncol) {
-        RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
-        return delegate.Rf_allocMatrix(mode, nrow, ncol);
-    }
-
-    @Override
-    public int Rf_nrows(Object x) {
-        RFFIUtils.traceUpCall("Rf_nrows", x);
-        return delegate.Rf_nrows(x);
-    }
-
-    @Override
-    public int Rf_ncols(Object x) {
-        RFFIUtils.traceUpCall("Rf_ncols", x);
-        return delegate.Rf_ncols(x);
-    }
-
-    @Override
-    public int LENGTH(Object x) {
-        RFFIUtils.traceUpCall("LENGTH", x);
-        return delegate.LENGTH(x);
-    }
-
-    @Override
-    public int SET_STRING_ELT(Object x, long i, Object v) {
-        RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
-        return delegate.SET_STRING_ELT(x, i, v);
-    }
-
-    @Override
-    public int SET_VECTOR_ELT(Object x, long i, Object v) {
-        RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
-        return delegate.SET_VECTOR_ELT(x, i, v);
-    }
-
-    @Override
-    public Object RAW(Object x) {
-        RFFIUtils.traceUpCall("RAW", x);
-        return delegate.RAW(x);
-    }
-
-    @Override
-    public Object LOGICAL(Object x) {
-        RFFIUtils.traceUpCall("LOGICAL", x);
-        return delegate.LOGICAL(x);
-    }
-
-    @Override
-    public Object INTEGER(Object x) {
-        RFFIUtils.traceUpCall("INTEGER", x);
-        return delegate.INTEGER(x);
-    }
-
-    @Override
-    public Object REAL(Object x) {
-        RFFIUtils.traceUpCall("REAL", x);
-        return delegate.REAL(x);
-    }
-
-    @Override
-    public Object STRING_ELT(Object x, long i) {
-        RFFIUtils.traceUpCall("STRING_ELT", x, i);
-        return delegate.STRING_ELT(x, i);
-    }
-
-    @Override
-    public Object VECTOR_ELT(Object x, long i) {
-        RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
-        return delegate.VECTOR_ELT(x, i);
-    }
-
-    @Override
-    public int NAMED(Object x) {
-        RFFIUtils.traceUpCall("NAMED", x);
-        return delegate.NAMED(x);
-    }
-
-    @Override
-    public Object SET_NAMED_FASTR(Object x, int v) {
-        RFFIUtils.traceUpCall("SET_NAMED_FASTR", x, v);
-        return delegate.SET_NAMED_FASTR(x, v);
-    }
-
-    @Override
-    public Object SET_TYPEOF_FASTR(Object x, int v) {
-        RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
-        return delegate.SET_TYPEOF_FASTR(x, v);
-    }
-
-    @Override
-    public int TYPEOF(Object x) {
-        RFFIUtils.traceUpCall("TYPEOF", x);
-        return delegate.TYPEOF(x);
-    }
-
-    @Override
-    public int OBJECT(Object x) {
-        RFFIUtils.traceUpCall("OBJECT", x);
-        return delegate.OBJECT(x);
-    }
-
-    @Override
-    public Object Rf_duplicate(Object x, int deep) {
-        RFFIUtils.traceUpCall("Rf_duplicate", x, deep);
-        return delegate.Rf_duplicate(x, deep);
-    }
-
-    @Override
-    public long Rf_any_duplicated(Object x, int fromLast) {
-        RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
-        return delegate.Rf_any_duplicated(x, fromLast);
-    }
-
-    @Override
-    public Object PRINTNAME(Object x) {
-        RFFIUtils.traceUpCall("PRINTNAME", x);
-        return delegate.PRINTNAME(x);
-    }
-
-    @Override
-    public Object TAG(Object e) {
-        RFFIUtils.traceUpCall("TAG", e);
-        return delegate.TAG(e);
-    }
-
-    @Override
-    public Object CAR(Object e) {
-        RFFIUtils.traceUpCall("CAR", e);
-        return delegate.CAR(e);
-    }
-
-    @Override
-    public Object CDR(Object e) {
-        RFFIUtils.traceUpCall("CDR", e);
-        return delegate.CDR(e);
-    }
-
-    @Override
-    public Object CADR(Object e) {
-        RFFIUtils.traceUpCall("CADR", e);
-        return delegate.CADR(e);
-    }
-
-    @Override
-    public Object CADDR(Object e) {
-        RFFIUtils.traceUpCall("CADDR", e);
-        return delegate.CADDR(e);
-    }
-
-    @Override
-    public Object CDDR(Object e) {
-        RFFIUtils.traceUpCall("CDDR", e);
-        return delegate.CDDR(e);
-    }
-
-    @Override
-    public Object SET_TAG(Object x, Object y) {
-        RFFIUtils.traceUpCall("SET_TAG", x, y);
-        return delegate.SET_TAG(x, y);
-    }
-
-    @Override
-    public Object SETCAR(Object x, Object y) {
-        RFFIUtils.traceUpCall("SETCAR", x, y);
-        return delegate.SETCAR(x, y);
-    }
-
-    @Override
-    public Object SETCDR(Object x, Object y) {
-        RFFIUtils.traceUpCall("SETCDR", x, y);
-        return delegate.SETCDR(x, y);
-    }
-
-    @Override
-    public Object SETCADR(Object x, Object y) {
-        RFFIUtils.traceUpCall("SETCADR", x);
-        return delegate.SETCADR(x, y);
-    }
-
-    @Override
-    public Object SYMVALUE(Object x) {
-        RFFIUtils.traceUpCall("SYMVALUE", x);
-        return delegate.SYMVALUE(x);
-    }
-
-    @Override
-    public int SET_SYMVALUE(Object x, Object v) {
-        RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
-        return delegate.SET_SYMVALUE(x, v);
-    }
-
-    @Override
-    public int R_BindingIsLocked(Object sym, Object env) {
-        RFFIUtils.traceUpCall("R_BindingIsLocked", sym, env);
-        return delegate.R_BindingIsLocked(sym, env);
-    }
-
-    @Override
-    public Object R_FindNamespace(Object name) {
-        RFFIUtils.traceUpCall("R_FindNamespace", name);
-        return delegate.R_FindNamespace(name);
-    }
-
-    @Override
-    public Object Rf_eval(Object expr, Object env) {
-        RFFIUtils.traceUpCall("Rf_eval", expr, env);
-        return delegate.Rf_eval(expr, env);
-    }
-
-    @Override
-    public Object Rf_findFun(Object symbolObj, Object envObj) {
-        RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
-        return delegate.Rf_findFun(symbolObj, envObj);
-    }
-
-    @Override
-    public Object Rf_GetOption1(Object tag) {
-        RFFIUtils.traceUpCall("Rf_GetOption1", tag);
-        return delegate.Rf_GetOption1(tag);
-    }
-
-    @Override
-    public int Rf_gsetVar(Object symbol, Object value, Object rho) {
-        RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
-        return delegate.Rf_gsetVar(symbol, value, rho);
-    }
-
-    @Override
-    public int DUPLICATE_ATTRIB(Object to, Object from) {
-        RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
-        return delegate.DUPLICATE_ATTRIB(to, from);
-    }
-
-    @Override
-    public int R_compute_identical(Object x, Object y, int flags) {
-        RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
-        return delegate.R_compute_identical(x, y, flags);
-    }
-
-    @Override
-    public int Rf_copyListMatrix(Object s, Object t, int byrow) {
-        RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
-        return delegate.Rf_copyListMatrix(s, t, byrow);
-    }
-
-    @Override
-    public int Rf_copyMatrix(Object s, Object t, int byrow) {
-        RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
-        return delegate.Rf_copyMatrix(s, t, byrow);
-    }
-
-    @Override
-    public Object R_tryEval(Object expr, Object env, int silent) {
-        RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
-        return delegate.R_tryEval(expr, env, silent);
-    }
-
-    @Override
-    public Object R_ToplevelExec() {
-        RFFIUtils.traceUpCall("R_TopLevelExec");
-        return delegate.R_ToplevelExec();
-    }
-
-    @Override
-    public int RDEBUG(Object x) {
-        RFFIUtils.traceUpCall("RDEBUG", x);
-        return delegate.RDEBUG(x);
-    }
-
-    @Override
-    public int SET_RDEBUG(Object x, int v) {
-        RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
-        return delegate.SET_RDEBUG(x, v);
-    }
-
-    @Override
-    public int RSTEP(Object x) {
-        RFFIUtils.traceUpCall("RSTEP", x);
-        return delegate.RSTEP(x);
-    }
-
-    @Override
-    public int SET_RSTEP(Object x, int v) {
-        RFFIUtils.traceUpCall("SET_RSTEP", x, v);
-        return delegate.SET_RSTEP(x, v);
-    }
-
-    @Override
-    public Object ENCLOS(Object x) {
-        RFFIUtils.traceUpCall("ENCLOS", x);
-        return delegate.ENCLOS(x);
-    }
-
-    @Override
-    public Object PRVALUE(Object x) {
-        RFFIUtils.traceUpCall("PRVALUE", x);
-        return delegate.PRVALUE(x);
-    }
-
-    @Override
-    public Object R_ParseVector(Object text, int n, Object srcFile) {
-        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) {
-        RFFIUtils.traceUpCall("R_lsInternal3", envArg, allArg, sortedArg);
-        return delegate.R_lsInternal3(envArg, allArg, sortedArg);
-    }
-
-    @Override
-    public String R_HomeDir() {
-        RFFIUtils.traceUpCall("R_HomeDir");
-        return delegate.R_HomeDir();
-    }
-
-    @Override
-    public int R_CleanUp(int sa, int status, int runlast) {
-        RFFIUtils.traceUpCall("R_Cleanup", sa, status, runlast);
-        return delegate.R_CleanUp(sa, status, runlast);
-    }
-
-    @Override
-    public Object R_GlobalContext() {
-        RFFIUtils.traceUpCall("R_GlobalContext");
-        return delegate.R_GlobalContext();
-    }
-
-    @Override
-    public Object R_GlobalEnv() {
-        RFFIUtils.traceUpCall("R_GlobalEnv");
-        return delegate.R_GlobalEnv();
-    }
-
-    @Override
-    public Object R_BaseEnv() {
-        RFFIUtils.traceUpCall("R_BaseEnv");
-        return delegate.R_BaseEnv();
-    }
-
-    @Override
-    public Object R_BaseNamespace() {
-        RFFIUtils.traceUpCall("R_BaseNamespace");
-        return delegate.R_BaseNamespace();
-    }
-
-    @Override
-    public Object R_NamespaceRegistry() {
-        RFFIUtils.traceUpCall("R_NamespaceRegistry");
-        return delegate.R_NamespaceRegistry();
-    }
-
-    @Override
-    public int R_Interactive() {
-        RFFIUtils.traceUpCall("isInteractive");
-        return delegate.R_Interactive();
-    }
-
-    @Override
-    public int IS_S4_OBJECT(Object x) {
-        RFFIUtils.traceUpCall("isS4Object");
-        return delegate.IS_S4_OBJECT(x);
-    }
-
-    @Override
-    public int SET_S4_OBJECT(Object x) {
-        RFFIUtils.traceUpCall("setS4Object");
-        return delegate.SET_S4_OBJECT(x);
-    }
-
-    @Override
-    public int UNSET_S4_OBJECT(Object x) {
-        RFFIUtils.traceUpCall("unsetS4Object");
-        return delegate.UNSET_S4_OBJECT(x);
-    }
-
-    @Override
-    public int Rprintf(Object message) {
-        RFFIUtils.traceUpCall("Rprintf", message);
-        return delegate.Rprintf(message);
-    }
-
-    @Override
-    public int GetRNGstate() {
-        RFFIUtils.traceUpCall("GetRNGstate");
-        return delegate.GetRNGstate();
-    }
-
-    @Override
-    public int PutRNGstate() {
-        RFFIUtils.traceUpCall("PutRNGstate");
-        return delegate.PutRNGstate();
-    }
-
-    @Override
-    public double unif_rand() {
-        RFFIUtils.traceUpCall("unif_rand");
-        return delegate.unif_rand();
-    }
-
-    @Override
-    public Object R_getGlobalFunctionContext() {
-        RFFIUtils.traceUpCall("R_getGlobalFunctionContext");
-        return delegate.R_getGlobalFunctionContext();
-    }
-
-    @Override
-    public Object R_getParentFunctionContext(Object c) {
-        RFFIUtils.traceUpCall("R_getParentFunctionContext");
-        return delegate.R_getParentFunctionContext(c);
-    }
-
-    @Override
-    public Object R_getContextEnv(Object c) {
-        RFFIUtils.traceUpCall("R_getContextEnv", c);
-        return delegate.R_getContextEnv(c);
-    }
-
-    @Override
-    public Object R_getContextFun(Object c) {
-        RFFIUtils.traceUpCall("R_getContextFun", c);
-        return delegate.R_getContextFun(c);
-    }
-
-    @Override
-    public Object R_getContextCall(Object c) {
-        RFFIUtils.traceUpCall("R_getContextCall", c);
-        return delegate.R_getContextCall(c);
-    }
-
-    @Override
-    public Object R_getContextSrcRef(Object c) {
-        RFFIUtils.traceUpCall("R_getContextSrcRef", c);
-        return delegate.R_getContextSrcRef(c);
-    }
-
-    @Override
-    public int R_insideBrowser() {
-        RFFIUtils.traceUpCall("R_insideBrowser");
-        return delegate.R_insideBrowser();
-    }
-
-    @Override
-    public int R_isGlobal(Object c) {
-        RFFIUtils.traceUpCall("R_isGlobal", c);
-        return delegate.R_isGlobal(c);
-    }
-
-    @Override
-    public int R_isEqual(Object x, Object y) {
-        RFFIUtils.traceUpCall("isEqual", x, y);
-        return delegate.R_isEqual(x, y);
-    }
-
-    @Override
-    public Object Rf_classgets(Object x, Object y) {
-        RFFIUtils.traceUpCall("Rf_classgets", x, y);
-        return delegate.Rf_classgets(x, y);
-    }
-
-    @Override
-    public RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
-        RFFIUtils.traceUpCall("R_MakeExternalPtr", addr, tag, prot);
-        return delegate.R_MakeExternalPtr(addr, tag, prot);
-    }
-
-    @Override
-    public long R_ExternalPtrAddr(Object x) {
-        RFFIUtils.traceUpCall("R_ExternalPtrAddr", x);
-        return delegate.R_ExternalPtrAddr(x);
-    }
-
-    @Override
-    public Object R_ExternalPtrTag(Object x) {
-        RFFIUtils.traceUpCall("R_ExternalPtrTag", x);
-        return delegate.R_ExternalPtrTag(x);
-    }
-
-    @Override
-    public Object R_ExternalPtrProtected(Object x) {
-        RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
-        return delegate.R_ExternalPtrProtected(x);
-    }
-
-    @Override
-    public int R_SetExternalPtrAddr(Object x, long addr) {
-        RFFIUtils.traceUpCall("R_SetExternalPtrAddr", x);
-        return delegate.R_SetExternalPtrAddr(x, addr);
-    }
-
-    @Override
-    public int R_SetExternalPtrTag(Object x, Object tag) {
-        RFFIUtils.traceUpCall("R_SetExternalPtrTag", x);
-        return delegate.R_SetExternalPtrTag(x, tag);
-    }
-
-    @Override
-    public int R_SetExternalPtrProtected(Object x, Object prot) {
-        RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
-        return delegate.R_SetExternalPtrProtected(x, prot);
-    }
-
-    @Override
-    public Object R_NewHashedEnv(Object parent, Object initialSize) {
-        RFFIUtils.traceUpCall("R_NewHashedEnv", parent, initialSize);
-        return delegate.R_NewHashedEnv(parent, initialSize);
-    }
-
-    @Override
-    public int PRSEEN(Object x) {
-        RFFIUtils.traceUpCall("PRSEEN", x);
-        return delegate.PRSEEN(x);
-    }
-
-    @Override
-    public Object PRENV(Object x) {
-        RFFIUtils.traceUpCall("PRENV", x);
-        return delegate.PRENV(x);
-    }
-
-    @Override
-    public Object R_PromiseExpr(Object x) {
-        RFFIUtils.traceUpCall("R_PromiseExpr", x);
-        return delegate.R_PromiseExpr(x);
-    }
-
-    @Override
-    public Object PRCODE(Object x) {
-        RFFIUtils.traceUpCall("PRCODE", x);
-        return delegate.PRCODE(x);
-    }
-
-    @Override
-    public Object R_CHAR(Object x) {
-        RFFIUtils.traceUpCall("R_CHAR", x);
-        return delegate.R_CHAR(x);
-    }
-
-    @Override
-    public Object R_new_custom_connection(Object description, Object mode, Object className, Object readAddr) {
-        RFFIUtils.traceUpCall("R_new_custom_connection", description, mode, className, readAddr);
-        return delegate.R_new_custom_connection(description, mode, className, readAddr);
-    }
-
-    @Override
-    public int R_ReadConnection(int fd, Object buf) {
-        RFFIUtils.traceUpCall("R_ReadConnection", fd, buf);
-        return delegate.R_ReadConnection(fd, buf);
-    }
-
-    @Override
-    public int R_WriteConnection(int fd, Object buf) {
-        RFFIUtils.traceUpCall("R_WriteConnection", fd, buf);
-        return delegate.R_WriteConnection(fd, buf);
-    }
-
-    @Override
-    public Object R_GetConnection(int fd) {
-        RFFIUtils.traceUpCall("R_GetConnection", fd);
-        return delegate.R_GetConnection(fd);
-    }
-
-    @Override
-    public String getSummaryDescription(Object x) {
-        RFFIUtils.traceUpCall("getSummaryDescription", x);
-        return delegate.getSummaryDescription(x);
-    }
-
-    @Override
-    public String getConnectionClassString(Object x) {
-        RFFIUtils.traceUpCall("getConnectionClassString", x);
-        return delegate.getConnectionClassString(x);
-    }
-
-    @Override
-    public String getOpenModeString(Object x) {
-        RFFIUtils.traceUpCall("getOpenModeString", x);
-        return delegate.getOpenModeString(x);
-    }
-
-    @Override
-    public boolean isSeekable(Object x) {
-        RFFIUtils.traceUpCall("isSeekable", x);
-        return delegate.isSeekable(x);
-    }
-
-    @Override
-    public Object R_do_slot(Object o, Object name) {
-        RFFIUtils.traceUpCall("R_do_slot", o, name);
-        return delegate.R_do_slot(o, name);
-    }
-
-    @Override
-    public Object R_do_slot_assign(Object o, Object name, Object value) {
-        RFFIUtils.traceUpCall("R_do_slot", o, name, value);
-        return delegate.R_do_slot_assign(o, name, value);
-    }
-
-    @Override
-    public Object R_MethodsNamespace() {
-        RFFIUtils.traceUpCall("R_MethodsNamespace");
-        return delegate.R_MethodsNamespace();
-    }
-
-    @Override
-    public int Rf_str2type(Object name) {
-        RFFIUtils.traceUpCall("Rf_str2type");
-        return delegate.Rf_str2type(name);
-    }
-
-    @Override
-    public double Rf_dunif(double a, double b, double c, int d) {
-        RFFIUtils.traceUpCall("Rf_dunif", a, b, c, d);
-        return delegate.Rf_dunif(a, b, c, d);
-    }
-
-    @Override
-    public double Rf_qunif(double a, double b, double c, int d, int e) {
-        RFFIUtils.traceUpCall("Rf_qunif", a, b, c, d, e);
-        return delegate.Rf_qunif(a, b, c, d, e);
-    }
-
-    @Override
-    public double Rf_punif(double a, double b, double c, int d, int e) {
-        RFFIUtils.traceUpCall("Rf_punif", a, b, c, d, e);
-        return delegate.Rf_punif(a, b, c, d, e);
-    }
-
-    @Override
-    public double Rf_runif(double a, double b) {
-        RFFIUtils.traceUpCall("Rf_runif", a, b);
-        return delegate.Rf_runif(a, b);
-    }
-
-    @Override
-    public Object Rf_namesgets(Object vec, Object val) {
-        RFFIUtils.traceUpCall("Rf_namesgets", vec, val);
-        return delegate.Rf_namesgets(vec, val);
-    }
-
-    @Override
-    public int Rf_copyMostAttrib(Object x, Object y) {
-        RFFIUtils.traceUpCall("Rf_copyMostAttrib", x, y);
-        return delegate.Rf_copyMostAttrib(x, y);
-    }
-
-    @Override
-    public Object Rf_VectorToPairList(Object x) {
-        RFFIUtils.traceUpCall("Rf_VectorToPairlist", x);
-        return delegate.Rf_VectorToPairList(x);
-    }
-
-    @Override
-    public Object Rf_asCharacterFactor(Object x) {
-        RFFIUtils.traceUpCall("Rf_asCharacterFactor", x);
-        return delegate.Rf_asCharacterFactor(x);
-    }
-
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java
index ce76b9870d2ec52f83cae85f83445971d7ac9573..e24e5a04c5616b077644982bace7c0dd66b9c0c9 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java
@@ -25,17 +25,17 @@ package com.oracle.truffle.r.ffi.impl.interop.pkginit;
 import com.oracle.truffle.api.interop.MessageResolution;
 import com.oracle.truffle.api.interop.Resolve;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.ffi.impl.upcalls.UpCallUnwrap;
+import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 
 @MessageResolution(receiverType = SetDotSymbolValuesCall.class)
 public class SetDotSymbolValuesCallMR {
     @Resolve(message = "EXECUTE")
     public abstract static class SetDotSymbolValuesCallExecute extends Node {
-        @Child private UpCallUnwrap unwrap = new UpCallUnwrap();
+        @Child private FFIUnwrapNode unwrap = new FFIUnwrapNode();
 
         protected java.lang.Object access(SetDotSymbolValuesCall receiver, Object[] arguments) {
-            return receiver.pkgInitUpCalls.setDotSymbolValues((DLLInfo) arguments[0], (String) unwrap.unwrap(arguments[1]), arguments[2], (int) arguments[3]);
+            return receiver.pkgInitUpCalls.setDotSymbolValues((DLLInfo) arguments[0], (String) unwrap.execute(arguments[1]), arguments[2], (int) arguments[3]);
         }
     }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java
index 70ad5c69a4f2269113074d15c04c06c57c013e18..7f9acf474a8ee85c7b4db8a2c67e85cf4fc625f9 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNI_Call.java
@@ -138,13 +138,13 @@ public class JNI_Call implements CallRFFI {
 
     @TruffleBoundary
     private static void initialize() {
-        UpCallsRFFI upCallsRFFIImpl = RFFIUtils.initialize(new JNIUpCallsRFFIImpl());
+        RFFIUtils.initializeTracing();
 
         if (traceEnabled()) {
             traceDownCall("initialize");
         }
         try {
-            initialize(upCallsRFFIImpl, RFFIVariables.initialize());
+            initialize(new JNIUpCallsRFFIImpl(), RFFIVariables.initialize());
         } finally {
             if (traceEnabled()) {
                 traceDownCallReturn("initialize", null);
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
index cb72d9283acff60d5c7563922f843e324f2caad5..c8c93913a0f459dc3c43d1e3034918b0a9915a09 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_CallFactory.TruffleLLVM_In
 import com.oracle.truffle.r.ffi.impl.llvm.upcalls.BytesToNativeCharArrayCall;
 import com.oracle.truffle.r.ffi.impl.llvm.upcalls.CharSXPToNativeArrayCall;
 import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks;
-import com.oracle.truffle.r.ffi.impl.upcalls.UpCallUnwrap;
+import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode;
 import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -55,12 +55,11 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
 
 final class TruffleLLVM_Call implements CallRFFI {
-    private static UpCallsRFFI upCallsRFFI;
     private static TruffleLLVM_UpCallsRFFIImpl upCallsRFFIImpl;
 
     TruffleLLVM_Call() {
         upCallsRFFIImpl = new TruffleLLVM_UpCallsRFFIImpl();
-        upCallsRFFI = RFFIUtils.initialize(upCallsRFFIImpl);
+        RFFIUtils.initializeTracing();
     }
 
     static class ContextStateImpl implements RContext.ContextState {
@@ -73,7 +72,7 @@ final class TruffleLLVM_Call implements CallRFFI {
             RFFIFactory.getCallRFFI();
             if (!initDone) {
                 initVariables(context);
-                initCallbacks(context, upCallsRFFI);
+                initCallbacks(context, upCallsRFFIImpl);
                 initDone = true;
             }
             return this;
@@ -187,12 +186,12 @@ final class TruffleLLVM_Call implements CallRFFI {
     @ImportStatic({Message.class})
     abstract static class TruffleLLVM_InvokeCallNode extends Node implements InvokeCallNode {
 
-        @Child private UpCallUnwrap unwrap;
+        @Child private FFIUnwrapNode unwrap;
         private final boolean isVoid;
 
         protected TruffleLLVM_InvokeCallNode(boolean isVoid) {
             this.isVoid = isVoid;
-            this.unwrap = isVoid ? null : new UpCallUnwrap();
+            this.unwrap = isVoid ? null : new FFIUnwrapNode();
         }
 
         protected static ToNativeNode[] createConvertNodes(int length) {
@@ -229,7 +228,7 @@ final class TruffleLLVM_Call implements CallRFFI {
                 }
                 Object result = ForeignAccess.sendExecute(messageNode, nativeCallInfo.address.asTruffleObject(), args);
                 if (!isVoid) {
-                    result = unwrap.unwrap(result);
+                    result = unwrap.execute(result);
                 }
                 return result;
             } catch (InteropException t) {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
index 2e474e0ac64cc2758b89e88eb6158a6553e539e5..0efd2c10b1fab6696a0bd2f5b603c85cfeaf2a21 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
@@ -215,12 +215,12 @@ public class TruffleNFI_Call implements CallRFFI {
     }
 
     private static void initialize() {
-        UpCallsRFFI upCallsImpl = RFFIUtils.initialize(new TruffleNFI_UpCallsRFFIImpl());
+        RFFIUtils.initializeTracing();
         if (traceEnabled()) {
             traceDownCall("initialize");
         }
         try {
-            initCallbacks(upCallsImpl);
+            initCallbacks(new TruffleNFI_UpCallsRFFIImpl());
             initVariables();
             initReturnArray();
         } finally {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java
index de10716282dd189766cd122c954d30a2cca6e652..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java
@@ -1,122 +0,0 @@
-/*
- * 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.ffi.impl.nodes;
-
-import java.util.function.Supplier;
-
-import com.oracle.truffle.api.RootCallTarget;
-import com.oracle.truffle.api.Truffle;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.RootNode;
-import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CADDRNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CADRNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CARNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CDDRNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CDRNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.LENGTHNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.RDoNewObjectNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.RDoSlotAssignNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.RDoSlotNodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.RandFunctionsNodesFactory.RandFunction2NodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.RandFunctionsNodesFactory.RandFunction3_1NodeGen;
-import com.oracle.truffle.r.ffi.impl.nodes.RandFunctionsNodesFactory.RandFunction3_2NodeGen;
-import com.oracle.truffle.r.ffi.impl.upcalls.RFFIUpCallTable;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.nmath.distr.Unif;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
-
-public final class FFIUpCallRootNode extends RootNode {
-    private static final RootCallTarget[] rootCallTargets = new RootCallTarget[RFFIUpCallTable.values().length];
-
-    @Child private FFIUpCallNode theFFIUpCallNode;
-    private final int numArgs;
-
-    private FFIUpCallRootNode(FFIUpCallNode child) {
-        super(RContext.getInstance().getLanguage());
-        theFFIUpCallNode = child;
-        this.numArgs = child.numArgs();
-    }
-
-    @Override
-    public SourceSection getSourceSection() {
-        return RSyntaxNode.INTERNAL;
-    }
-
-    @Override
-    public Object execute(VirtualFrame frame) {
-        Object[] args = frame.getArguments();
-        switch (numArgs) {
-            case 0:
-                return ((FFIUpCallNode.Arg0) theFFIUpCallNode).executeObject();
-            case 1:
-                return ((FFIUpCallNode.Arg1) theFFIUpCallNode).executeObject(args[0]);
-            case 2:
-                return ((FFIUpCallNode.Arg2) theFFIUpCallNode).executeObject(args[0], args[1]);
-            case 3:
-                return ((FFIUpCallNode.Arg3) theFFIUpCallNode).executeObject(args[0], args[1], args[2]);
-            default:
-                throw RInternalError.shouldNotReachHere();
-        }
-    }
-
-    static void add(RFFIUpCallTable upCallMethod, Supplier<FFIUpCallNode> constructor) {
-
-        FFIUpCallRootNode rootNode = new FFIUpCallRootNode(constructor.get());
-        rootCallTargets[upCallMethod.ordinal()] = Truffle.getRuntime().createCallTarget(rootNode);
-    }
-
-    public static RootCallTarget getCallTarget(RFFIUpCallTable upCallMethod) {
-        RootCallTarget target = rootCallTargets[upCallMethod.ordinal()];
-        assert target != null;
-        return target;
-    }
-
-    public static void register() {
-        FFIUpCallRootNode.add(RFFIUpCallTable.ATTRIB, AttributesAccessNodesFactory.ATTRIBNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asReal, AsRealNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asLogical, AsLogicalNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asInteger, AsIntegerNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asChar, AsCharNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_coerceVector, CoerceNodes.CoerceVectorNode::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.CAR, CARNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.CDR, CDRNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.CADR, CADRNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.CADDR, CADDRNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.CDDR, CDDRNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.LENGTH, LENGTHNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.R_do_new_object, RDoNewObjectNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.R_do_slot, RDoSlotNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.R_do_slot_assign, RDoSlotAssignNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_runif, () -> RandFunction2NodeGen.create(new Unif.Runif()));
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_dunif, () -> RandFunction3_1NodeGen.create(new Unif.DUnif()));
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_qunif, () -> RandFunction3_2NodeGen.create(new Unif.QUnif()));
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_punif, () -> RandFunction3_2NodeGen.create(new Unif.PUnif()));
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_namesgets, MiscNodesFactory.NamesGetsNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.TAG, AttributesAccessNodesFactory.TAGNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_copyMostAttrib, AttributesAccessNodesFactory.CopyMostAttribNodeGen::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_VectorToPairList, CoerceNodes.VectorToPairListNode::create);
-        FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asCharacterFactor, CoerceNodes.AsCharacterFactor::create);
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/UpCallUnwrap.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
similarity index 96%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/UpCallUnwrap.java
rename to com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
index 65f03708e12c29ecfbe6aa08b61dbdc51f519731..9b83b536d85890273bf6027ba91be51a4dc8a0c6 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/UpCallUnwrap.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
@@ -35,10 +35,11 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
-public final class UpCallUnwrap extends Node {
+public final class FFIUnwrapNode extends Node {
 
     @Child private Node isBoxed;
     @Child private Node unbox;
+
     private final BranchProfile nativePointerProfile = isLLVM() ? BranchProfile.create() : null;
 
     /**
@@ -55,7 +56,7 @@ public final class UpCallUnwrap extends Node {
      * to do.</li>
      * </ul>
      */
-    public Object unwrap(Object x) {
+    public Object execute(Object x) {
         if (x instanceof RTruffleObject) {
             return x;
         } else if (x instanceof TruffleObject) {
@@ -98,4 +99,8 @@ public final class UpCallUnwrap extends Node {
     private static TruffleObject checkNativePointer(TruffleObject xto) {
         return NativePointer.check(xto);
     }
+
+    public static FFIUnwrapNode create() {
+        return new FFIUnwrapNode();
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..662dcfd26b378c93d55fa5883f2dca1cbf8f56ae
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
@@ -0,0 +1,37 @@
+/*
+ * 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.ffi.impl.upcalls;
+
+import com.oracle.truffle.api.nodes.Node;
+
+public final class FFIWrapNode extends Node {
+
+    @SuppressWarnings("static-method")
+    public Object execute(Object value) {
+        return value;
+    }
+
+    public static FFIWrapNode create() {
+        return new FFIWrapNode();
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
index b569971b0250b159f2b9275e4b4157c5a17a0201..2b82ab0a1728739d32e7a51be3eb268de114fd2a 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
@@ -35,11 +35,6 @@ import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CDRNode;
 import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes.LENGTHNode;
 import com.oracle.truffle.r.ffi.processor.RFFICstring;
 import com.oracle.truffle.r.ffi.processor.RFFIUpCallNode;
-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;
 
 /**
  * This class defines methods that match the functionality of the macro/function definitions in the
@@ -64,13 +59,13 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 public interface StdUpCallsRFFI {
     // Checkstyle: stop method name check
 
-    RIntVector Rf_ScalarInteger(int value);
+    Object Rf_ScalarInteger(int value);
 
-    RLogicalVector Rf_ScalarLogical(int value);
+    Object Rf_ScalarLogical(int value);
 
-    RDoubleVector Rf_ScalarDouble(double value);
+    Object Rf_ScalarDouble(double value);
 
-    RStringVector Rf_ScalarString(Object value);
+    Object Rf_ScalarString(Object value);
 
     @RFFIUpCallNode(AsIntegerNode.class)
     int Rf_asInteger(Object x);
@@ -266,7 +261,7 @@ public interface StdUpCallsRFFI {
 
     Object Rf_classgets(Object x, Object y);
 
-    RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot);
+    Object R_MakeExternalPtr(long addr, Object tag, Object prot);
 
     long R_ExternalPtrAddr(Object x);
 
diff --git a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
index b40b966fbe08676165a700c175e0fcb90abe95b5..d3e84a3759d1a9f28c7ef2be7d6cb0c1027c6ef5 100644
--- a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
+++ b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
@@ -38,6 +38,7 @@ import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.MirroredTypeException;
@@ -46,7 +47,6 @@ import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Types;
 import javax.tools.Diagnostic;
 import javax.tools.Diagnostic.Kind;
-
 import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
 import javax.tools.StandardLocation;
@@ -163,38 +163,48 @@ public final class FFIProcessor extends AbstractProcessor {
 
     private void generateCallClass(ExecutableElement m) throws IOException {
         RFFIUpCallNode nodeAnnotation = m.getAnnotation(RFFIUpCallNode.class);
-        String node = null;
+        String nodeClassName = null;
+        TypeElement nodeClass = null;
         if (nodeAnnotation != null) {
             try {
                 nodeAnnotation.value();
             } catch (MirroredTypeException e) {
-                node = ((TypeElement) processingEnv.getTypeUtils().asElement(e.getTypeMirror())).getQualifiedName().toString();
+                nodeClass = (TypeElement) processingEnv.getTypeUtils().asElement(e.getTypeMirror());
+                nodeClassName = nodeClass.getQualifiedName().toString();
             }
         }
         // process arguments first to see if unwrap is necessary
         List<? extends VariableElement> params = m.getParameters();
         StringBuilder arguments = new StringBuilder();
-        int unwrapCount = 0;
+        StringBuilder unwrapNodes = new StringBuilder();
         for (int i = 0; i < params.size(); i++) {
             if (i != 0) {
                 arguments.append(", ");
             }
-            String paramTypeName = getTypeName(params.get(i).asType());
-            boolean isScalar = true;
+            TypeMirror paramType = params.get(i).asType();
+            String paramName = params.get(i).getSimpleName().toString();
+            String paramTypeName = getTypeName(paramType);
+            boolean isScalar = paramType.getKind().isPrimitive();
             boolean needCast = !paramTypeName.equals("java.lang.Object");
             if (needCast) {
                 arguments.append('(').append(paramTypeName).append(") ");
             }
-            if (isScalar) {
-                arguments.append("unwrap").append(unwrapCount).append(".unwrap(");
-                unwrapCount++;
+            if (!isScalar) {
+                arguments.append(paramName).append("Unwrap").append(".execute(");
+                unwrapNodes.append("                @Child private FFIUnwrapNode ").append(paramName).append("Unwrap").append(" = FFIUnwrapNode.create();\n");
             }
             arguments.append("arguments.get(").append(i).append(")");
-            if (isScalar) {
+            if (!isScalar) {
                 arguments.append(')');
             }
         }
 
+        TypeKind returnKind = m.getReturnType().getKind();
+        boolean needsReturnWrap = returnKind != TypeKind.VOID && !returnKind.isPrimitive() && !"java.lang.String".equals(getTypeName(m.getReturnType()));
+        if (needsReturnWrap) {
+            unwrapNodes.append("                @Child private FFIWrapNode returnWrap").append(" = FFIWrapNode.create();\n");
+        }
+
         String name = m.getSimpleName().toString();
         String callName = name + "Call";
         JavaFileObject fileObj = processingEnv.getFiler().createSourceFile("com.oracle.truffle.r.ffi.impl.upcalls." + callName);
@@ -211,59 +221,85 @@ public final class FFIProcessor extends AbstractProcessor {
         w.append("import com.oracle.truffle.api.interop.ForeignAccess;\n");
         w.append("import com.oracle.truffle.api.interop.TruffleObject;\n");
         w.append("import com.oracle.truffle.api.nodes.RootNode;\n");
+        w.append("import com.oracle.truffle.r.ffi.impl.common.RFFIUtils;\n");
         w.append("import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;\n");
         w.append("import com.oracle.truffle.r.runtime.data.RTruffleObject;\n");
         w.append("\n");
         w.append("// Checkstyle: stop method name check\n");
         w.append("\n");
-        w.append("final class ").append(callName).append(" implements RTruffleObject {\n");
+        w.append("final class " + callName + " implements RTruffleObject {\n");
         w.append('\n');
-        if (node == null) {
+        if (nodeClass == null) {
             w.append("    private final UpCallsRFFI upCallsImpl;\n");
             w.append('\n');
         }
-        w.append("    ").append(callName).append("(UpCallsRFFI upCallsImpl) {\n");
+        w.append("    " + callName + "(UpCallsRFFI upCallsImpl) {\n");
         w.append("        assert upCallsImpl != null;\n");
-        if (node == null) {
+        if (nodeClass == null) {
             w.append("        this.upCallsImpl = upCallsImpl;\n");
         }
         w.append("    }\n");
         w.append('\n');
-        w.append("    private static final class ").append(callName).append("Factory extends AbstractDowncallForeign {\n");
+        w.append("    private static final class " + callName + "Factory extends AbstractDowncallForeign {\n");
         w.append("        @Override\n");
         w.append("        public boolean canHandle(TruffleObject obj) {\n");
-        w.append("            return obj instanceof ").append(callName).append(";\n");
+        w.append("            return obj instanceof " + callName + ";\n");
         w.append("        }\n");
         w.append("\n");
         w.append("        @Override\n");
         w.append("        public CallTarget accessExecute(int argumentsLength) {\n");
         w.append("            return Truffle.getRuntime().createCallTarget(new RootNode(null) {\n");
         w.append("\n");
-        if (unwrapCount > 0) {
-            for (int i = 0; i < unwrapCount; i++) {
-                w.append("                @Child private UpCallUnwrap unwrap").append(Integer.toString(i)).append(" = new UpCallUnwrap();\n");
-            }
+        if (unwrapNodes.length() > 0) {
+            w.append(unwrapNodes);
             w.append("\n");
         }
-        if (node != null) {
-            w.append("                @Child private ").append(node).append(" node").append(" = ").append(node).append(".create();\n");
+        if (nodeClass != null) {
+            boolean createFunction = false;
+            for (Element element : nodeClass.getEnclosedElements()) {
+                if (element.getKind() == ElementKind.METHOD && element.getModifiers().contains(Modifier.STATIC) && "create".equals(element.getSimpleName().toString())) {
+                    createFunction = true;
+                    break;
+                }
+            }
+            if (createFunction) {
+                w.append("                @Child private " + nodeClassName + " node = " + nodeClassName + ".create();\n");
+            } else if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
+                w.append("                @Child private " + nodeClassName + " node;\n");
+                processingEnv.getMessager().printMessage(Kind.ERROR, "Need static create for abstract classes", m);
+            } else {
+                w.append("                @Child private " + nodeClassName + " node = new " + nodeClassName + "();\n");
+            }
             w.append("\n");
         }
         w.append("                @Override\n");
         w.append("                public Object execute(VirtualFrame frame) {\n");
         w.append("                    List<Object> arguments = ForeignAccess.getArguments(frame);\n");
-        w.append("                    assert arguments.size() == ").append(Integer.toString(params.size())).append(" : \"wrong number of arguments passed to ").append(name).append("\";\n");
-        if (node != null) {
-            w.append("                    return node.executeObject(").append(arguments).append(");\n");
+        w.append("                    assert arguments.size() == " + params.size() + " : \"wrong number of arguments passed to " + name + "\";\n");
+        w.append("                    if (RFFIUtils.traceEnabled) {\n");
+        w.append("                        RFFIUtils.traceUpCall(\"" + name + "\", arguments);\n");
+        w.append("                    }\n");
+        w.append("                    return ");
+        if (needsReturnWrap) {
+            w.append("returnWrap.execute(");
+        }
+        if (nodeClass != null) {
+            w.append("node.executeObject");
+        } else {
+            w.append("((" + callName + ") ForeignAccess.getReceiver(frame)).upCallsImpl." + name);
+        }
+        w.append("(" + arguments + ")");
+        if (needsReturnWrap) {
+            w.append(");\n");
         } else {
-            w.append("                    return ((").append(callName).append(") ForeignAccess.getReceiver(frame)).upCallsImpl.").append(name).append("(").append(arguments).append(");\n");
+            w.append(";\n");
         }
         w.append("                }\n");
         w.append("            });\n");
         w.append("        }\n");
         w.append("    }\n");
         w.append("\n");
-        w.append("    private static final ForeignAccess ACCESS = ForeignAccess.create(new ").append(callName).append("Factory(), null);\n");
+        w.append("    private static final ForeignAccess ACCESS = ForeignAccess.create(new " + callName + "Factory(), null);\n");
         w.append("\n");
         w.append("    @Override\n");
         w.append("    public ForeignAccess getForeignAccess() {\n");
@@ -276,8 +312,8 @@ public final class FFIProcessor extends AbstractProcessor {
     private void generateCallbacks(ExecutableElement[] methods) throws IOException {
         JavaFileObject fileObj = processingEnv.getFiler().createSourceFile("com.oracle.truffle.r.ffi.impl.upcalls.Callbacks");
         Writer w = fileObj.openWriter();
-        w.append("// GENERATED; DO NOT EDIT\n");
-        w.append("package ").append("com.oracle.truffle.r.ffi.impl.upcalls").append(";\n\n");
+        w.append("// GENERATED; DO NOT EDIT\n\n");
+        w.append("package com.oracle.truffle.r.ffi.impl.upcalls;\n\n");
         w.append("import com.oracle.truffle.api.interop.TruffleObject;\n");
         w.append("import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;\n");
         w.append("import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;\n\n");
@@ -321,7 +357,7 @@ public final class FFIProcessor extends AbstractProcessor {
         for (int i = 0; i < lparams; i++) {
             VariableElement param = params.get(i);
             RFFICstring[] annotations = param.getAnnotationsByType(RFFICstring.class);
-            String nfiParam = nfiParamName(getTypeName(param.asType()), annotations.length == 0 ? null : annotations[0]);
+            String nfiParam = nfiParamName(param.asType(), annotations.length == 0 ? null : annotations[0], false, param);
             sb.append(nfiParam);
             if (i != lparams - 1) {
                 sb.append(", ");
@@ -329,19 +365,20 @@ public final class FFIProcessor extends AbstractProcessor {
         }
         sb.append(')');
         sb.append(" : ");
-        sb.append(nfiParamName(getTypeName(m.getReturnType()), null));
+        sb.append(nfiParamName(m.getReturnType(), null, true, m));
         return sb.toString();
     }
 
-    private static String nfiParamName(String paramType, RFFICstring rffiCstring) {
-        switch (paramType) {
+    private String nfiParamName(TypeMirror paramType, RFFICstring rffiCstring, boolean isReturn, Element m) {
+        String paramTypeName = getTypeName(paramType);
+        switch (paramTypeName) {
             case "java.lang.Object":
                 if (rffiCstring == null) {
                     return "object";
                 } else {
                     return rffiCstring.convert() ? "string" : "pointer";
                 }
-            case "char":
+            case "boolean":
                 return "uint8";
             case "int":
                 return "sint32";
@@ -360,6 +397,14 @@ public final class FFIProcessor extends AbstractProcessor {
             case "byte[]":
                 return "[uint8]";
             default:
+                if (isReturn) {
+                    if ("java.lang.String".equals(paramTypeName)) {
+                        return "string";
+                    }
+                    processingEnv.getMessager().printMessage(Kind.ERROR, "Invalid return type " + paramTypeName, m);
+                } else {
+                    processingEnv.getMessager().printMessage(Kind.ERROR, "Invalid parameter type " + paramTypeName, m);
+                }
                 return "object";
         }
     }
diff --git a/com.oracle.truffle.r.native/Makefile b/com.oracle.truffle.r.native/Makefile
index 9c35cd4da67430a24da06d00f9d72cc5b3b55131..c28fbbcc384fd8d72dc14721f2fd1ce1ffea49f7 100644
--- a/com.oracle.truffle.r.native/Makefile
+++ b/com.oracle.truffle.r.native/Makefile
@@ -32,7 +32,7 @@ export GNUR_HOME = $(TOPDIR)/gnur/R-$(R_VERSION)
 
 
 ifndef FASTR_RFFI
-export FASTR_RFFI = jni
+export FASTR_RFFI = nfi
 endif
 
 # Completely accurate dependency analysis is very difficult for this project, so use a version number
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
index daf3e5a28c864d6f524bfec8e7a684ba68c7f9cb..605a94203f6d1c8c1b0318ffa34f38849cfd5e5c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
@@ -53,7 +53,7 @@ public abstract class RFFIFactory {
 
     private static final String FACTORY_TYPE_PROPERTY = "fastr.rffi.factory.type";
     private static final String FACTORY_CLASS_ENV = "FASTR_RFFI";
-    private static final Type DEFAULT_FACTORY = Type.JNI;
+    private static final Type DEFAULT_FACTORY = Type.NFI;
 
     /**
      * Singleton instance of the factory.