From a6f795795fae925e6a636520a846db6e7443294b Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Wed, 8 Feb 2017 14:40:39 -0800
Subject: [PATCH] rffi: refactor UpCallsRFFIImpl classes to ensure tracing
 always happens

---
 .../ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java |    6 +-
 .../r/nodes/ffi/JavaUpCallsRFFIImpl.java      | 1145 +++++++++++++++
 .../truffle/r/nodes/ffi/RFFIUpCallMethod.java |   16 +-
 .../r/nodes/ffi/TraceUpCallsAdapter.java      |  892 ------------
 .../truffle/r/nodes/ffi/UpCallsRFFIImpl.java  | 1261 +++++------------
 .../truffle/r/runtime/ffi/jni/JNI_Call.java   |    5 +-
 6 files changed, 1514 insertions(+), 1811 deletions(-)
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
 delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TraceUpCallsAdapter.java

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 b903c34a33..d5f87c5150 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;
 
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 0000000000..8441fc32c7
--- /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
index 3074783733..fc354a931d 100644
--- 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
@@ -72,7 +72,7 @@ public enum RFFIUpCallMethod {
     R_SetExternalPtrTag("(object, object) : void"),
     R_ToplevelExec("() : object"),
     R_computeIdentical("(object, object, sint32) : sint32"),
-    R_do_MAKE_CLASS("(object) : object"),
+    R_do_MAKE_CLASS("(pointer) : object"),
     R_getContextCall("(object) : object"),
     R_getContextEnv("(object) : object"),
     R_getContextFun("(object) : object"),
@@ -104,7 +104,7 @@ public enum RFFIUpCallMethod {
     Rf_copyMatrix("(object, object, sint32) : void"),
     Rf_defineVar("(object, object, object) : void"),
     Rf_duplicate("(object, sint32) : object"),
-    Rf_error("(object) : void"),
+    Rf_error("(pointer) : void"),
     Rf_eval("(object, object) : object"),
     Rf_findVar("(object, object) : object"),
     Rf_findVarInFrame("(object, object) : object"),
@@ -112,18 +112,18 @@ public enum RFFIUpCallMethod {
     Rf_findfun("(object, object) : object"),
     Rf_getAttrib("(object, object) : object"),
     Rf_gsetVar("(object, object, object) : void"),
-    Rf_inherits("(object, object) : sint32"),
-    Rf_install("(object) : object"),
+    Rf_inherits("(pointer, object) : sint32"),
+    Rf_install("(pointer) : object"),
     Rf_isNull("(object) : sint32"),
     Rf_isString("(object) : sint32"),
     Rf_lengthgets("(object, sint32) : object"),
-    Rf_mkCharLenCE("(object, sint32, sint32) : object"),
+    Rf_mkCharLenCE("(pointer, sint32, sint32) : object"),
     Rf_ncols("(object) : sint32"),
     Rf_nrows("(object) : sint32"),
     Rf_setAttrib("(object, object, object) : void"),
-    Rf_warning("(object) : void"),
-    Rf_warningcall("(object, object) : void"),
-    Rprintf("(object) : void"),
+    Rf_warning("(pointer) : void"),
+    Rf_warningcall("(object, pointer) : void"),
+    Rprintf("(pointer) : void"),
     SETCADR("(object, object) : object"),
     SETCAR("(object, object) : object"),
     SETCDR("(object, object) : object"),
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 2c42a92eb5..0000000000
--- 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(Object bytes, int len, 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(Object 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, Object clazz) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
-        }
-        return 0;
-    }
-
-    @Override
-    public Object Rf_install(Object 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(Object msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_error", msg);
-        }
-    }
-
-    @Override
-    public void Rf_warning(Object msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_warning", msg);
-        }
-    }
-
-    @Override
-    public void Rf_warningcall(Object call, Object 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(Object 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, int initialSize) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, initialSize);
-        }
-        return null;
-    }
-}
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 dca6fda9cf..59a0dbc139 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();
-        }
+    private final UpCallsRFFI delegate;
+    private final boolean tracing;
+
+    public UpCallsRFFIImpl(UpCallsRFFI delegate) {
+        this.delegate = delegate;
         FFIUpCallRootNode.register();
+        tracing = RFFIUtils.traceEnabled();
     }
 
-    // Checkstyle: stop method name check
-
     @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(RFFIUpCallMethod.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(RFFIUpCallMethod.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(RFFIUpCallMethod.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(RFFIUpCallMethod.Rf_asChar).call(x);
+        return delegate.Rf_asChar(x);
     }
 
     @Override
     public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
-        if (tracer != null) {
-            tracer.Rf_mkCharLenCE(bytes, len, encoding);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
         }
-        // TODO: handle encoding properly
-        return CharSXPWrapper.create(new String((byte[]) 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(Object clazz) {
-        if (tracer != null) {
-            tracer.R_do_MAKE_CLASS(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);
-        }
-        // 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");
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
         }
-        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);
-        }
-        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;
-                }
-            }
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
         }
-        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);
-            }
-        }
-    }
-
-    @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;
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_setAttrib", obj, name, val);
+        }
+        delegate.Rf_setAttrib(obj, name, val);
     }
 
     @Override
     public int Rf_inherits(Object x, Object clazz) {
-        if (tracer != null) {
-            tracer.Rf_inherits(x, clazz);
+        if (tracing) {
+            RFFIUtils.traceUpCall("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;
-            }
-        }
-        return result;
+        return delegate.Rf_inherits(x, clazz);
     }
 
     @Override
     public Object Rf_install(Object name) {
-        if (tracer != null) {
-            tracer.Rf_install(name);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_install", name);
         }
-        return RDataFactory.createSymbolInterned((String) 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 (x == RNull.instance) {
-            return RDataFactory.createList();
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
         }
-        RPairList pl = (RPairList) x;
-        return pl.toRList();
+        return delegate.Rf_PairToVectorList(x);
     }
 
     @Override
     public void Rf_error(Object msg) {
-        if (tracer != null) {
-            tracer.Rf_error(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(Object msg) {
-        if (tracer != null) {
-            tracer.Rf_warning(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, Object msg) {
-        if (tracer != null) {
-            tracer.Rf_warningcall(call, msg);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
         }
-        RErrorHandling.warningcallRFFI(call, (String) 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(RFFIUpCallMethod.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(RFFIUpCallMethod.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(RFFIUpCallMethod.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(RFFIUpCallMethod.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(RFFIUpCallMethod.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(RFFIUpCallMethod.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);
-        }
-        REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
-        Object result = env.getParent();
-        if (result == null) {
-            result = RNull.instance;
+        if (tracing) {
+            RFFIUtils.traceUpCall("ENCLOS", x);
         }
-        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(Object message) {
-        if (tracer != null) {
-            tracer.Rprintf(message);
+        if (tracing) {
+            RFFIUtils.traceUpCall("Rprintf", message);
         }
-        RContext.getInstance().getConsoleHandler().print((String) 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();
+        if (tracing) {
+            RFFIUtils.traceUpCall("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;
+        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);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_getContextCall", c);
         }
-        RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
-        if (rCaller == RCaller.topLevel) {
-            return RNull.instance;
-        }
-        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, int initialSize) {
-        if (tracer != null) {
-            tracer.R_NewHashedEnv(parent, initialSize);
+        if (tracing) {
+            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, initialSize);
         }
-        REnvironment env = RDataFactory.createNewEnv(REnvironment.UNNAMED, true, 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 d7154d5a2c..b766682261 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);
-- 
GitLab