From e2413701f2d24b153254b97a4bb70bc70e92e2a7 Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Tue, 8 Aug 2017 15:23:58 +0200
Subject: [PATCH] more unification of NFI and LLVM ffi

---
 .../r/engine/TruffleRLanguageImpl.java        |   2 +-
 .../interop/RAbstractVectorAccessFactory.java |  16 +-
 .../r/ffi/impl/common/CallToNativeNode.java   | 161 ++++++++++++++++++
 .../r/ffi/impl/common/DownCallNode.java       |   5 +-
 .../ffi/impl/common/JavaUpCallsRFFIImpl.java  |  59 +++++--
 .../r/ffi/impl/common/NativeFunction.java     |  29 ----
 .../r/ffi/impl/jni/JNIUpCallsRFFIImpl.java    |  11 ++
 .../truffle/r/ffi/impl/llvm/LLVMFunction.java | 103 -----------
 .../r/ffi/impl/llvm/TruffleLLVM_Base.java     |  41 ++---
 .../impl/llvm/TruffleLLVM_DownCallNode.java   |   5 +-
 .../r/ffi/impl/llvm/TruffleLLVM_Lapack.java   |  53 +++---
 .../r/ffi/impl/llvm/TruffleLLVM_Misc.java     |   5 +-
 .../r/ffi/impl/llvm/TruffleLLVM_PCRE.java     |  21 +--
 .../r/ffi/impl/llvm/TruffleLLVM_RAppl.java    |  13 +-
 .../llvm/TruffleLLVM_RFFIContextState.java    |   8 +-
 .../llvm/TruffleLLVM_UpCallsRFFIImpl.java     |  37 ++++
 .../r/ffi/impl/llvm/TruffleLLVM_Zip.java      |   9 +-
 .../{NFIFunction.java => NativeFunction.java} |  56 +++---
 .../r/ffi/impl/nfi/TruffleNFI_Base.java       |  40 ++---
 .../r/ffi/impl/nfi/TruffleNFI_Call.java       |   5 +-
 .../ffi/impl/nfi/TruffleNFI_DownCallNode.java |   2 +-
 .../r/ffi/impl/nfi/TruffleNFI_Lapack.java     |  52 +++---
 .../r/ffi/impl/nfi/TruffleNFI_Misc.java       |   4 +-
 .../r/ffi/impl/nfi/TruffleNFI_PCRE.java       |  20 +--
 .../r/ffi/impl/nfi/TruffleNFI_PkgInit.java    |   1 -
 .../r/ffi/impl/nfi/TruffleNFI_RAppl.java      |  28 +--
 .../r/ffi/impl/nfi/TruffleNFI_Stats.java      |   8 +-
 .../impl/nfi/TruffleNFI_UpCallsRFFIImpl.java  |  55 ++++++
 .../r/ffi/impl/nfi/TruffleNFI_Zip.java        |  16 +-
 .../ffi/impl/nodes/AttributesAccessNodes.java |  21 ++-
 .../truffle/r/ffi/impl/nodes/CoerceNodes.java |   6 +-
 .../r/ffi/impl/upcalls/DLLUpCallsRFFI.java    |  72 ++++++++
 .../r/ffi/impl/upcalls/FFIUnwrapNode.java     |  66 +++----
 .../r/ffi/impl/upcalls/FFIWrapNode.java       |  36 ++++
 .../r/ffi/impl/upcalls/StdUpCallsRFFI.java    |  11 +-
 .../r/ffi/impl/upcalls/UpCallsRFFI.java       |   2 +-
 .../truffle/r/ffi/processor/FFIProcessor.java |   4 +-
 .../{base_rffi.h => base_rffi.c}              |  33 ++++
 .../fficall/src/truffle_common/lapack_rffi.c  |   1 -
 .../fficall/src/truffle_common/misc_rffi.c    |   2 +-
 .../{pcre_rffi.h => pcre_rffi.c}              |  10 +-
 .../zip_rffi.c                                |   6 +-
 .../fficall/src/truffle_llvm/base_rffi.c      |  69 --------
 .../fficall/src/truffle_llvm/pcre_rffi.c      |  25 ---
 .../fficall/src/truffle_nfi/base_rffi.c       |  33 ----
 .../fficall/src/truffle_nfi/pcre_rffi.c       |  13 --
 .../truffle/r/runtime/TempPathName.java       |   2 +-
 .../r/runtime/conn/ConnectionSupport.java     |   2 +-
 .../truffle/r/runtime/context/RContext.java   |  16 +-
 .../context/RForeignAccessFactory.java        |   3 +-
 .../r/runtime/data/NativeDataAccess.java      | 136 +++++++++++++++
 .../truffle/r/runtime/env/REnvironment.java   |  11 +-
 .../com/oracle/truffle/r/runtime/ffi/DLL.java |   2 +-
 .../truffle/r/runtime/ops/AccessVector.java   |  57 +++++++
 mx.fastr/mx_fastr_dists.py                    |   2 +-
 55 files changed, 956 insertions(+), 550 deletions(-)
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/CallToNativeNode.java
 delete mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/NativeFunction.java
 delete mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/LLVMFunction.java
 rename com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/{NFIFunction.java => NativeFunction.java} (77%)
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/DLLUpCallsRFFI.java
 rename com.oracle.truffle.r.native/fficall/src/truffle_common/{base_rffi.h => base_rffi.c} (81%)
 rename com.oracle.truffle.r.native/fficall/src/truffle_common/{pcre_rffi.h => pcre_rffi.c} (87%)
 rename com.oracle.truffle.r.native/fficall/src/{truffle_llvm => truffle_common}/zip_rffi.c (87%)
 delete mode 100644 com.oracle.truffle.r.native/fficall/src/truffle_llvm/base_rffi.c
 delete mode 100644 com.oracle.truffle.r.native/fficall/src/truffle_llvm/pcre_rffi.c
 delete mode 100644 com.oracle.truffle.r.native/fficall/src/truffle_nfi/base_rffi.c
 delete mode 100644 com.oracle.truffle.r.native/fficall/src/truffle_nfi/pcre_rffi.c
 create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
 create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/AccessVector.java

diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
index 65adfcfd0f..8fb818136f 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
@@ -123,7 +123,7 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage implements Scop
 
     @Override
     protected void disposeContext(RContext context) {
-        context.destroy();
+        context.dispose();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java
index b878ca95c1..9eb74afcf6 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java
@@ -52,7 +52,14 @@ import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
+import com.oracle.truffle.r.runtime.data.NativeDataAccess;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RLogical;
+import com.oracle.truffle.r.runtime.data.RLogicalVector;
+import com.oracle.truffle.r.runtime.data.RObject;
+import com.oracle.truffle.r.runtime.data.RRawVector;
+import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.interop.Foreign2R;
 import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen;
@@ -332,17 +339,12 @@ public final class RAbstractVectorAccessFactory implements Factory26 {
 
     @Override
     public CallTarget accessIsPointer() {
-        return Truffle.getRuntime().createCallTarget(new InteropRootNode() {
-            @Override
-            public Object execute(VirtualFrame frame) {
-                return false;
-            }
-        });
+        return NativeDataAccess.createIsPointer();
     }
 
     @Override
     public CallTarget accessAsPointer() {
-        return null;
+        return NativeDataAccess.createAsPointer();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/CallToNativeNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/CallToNativeNode.java
new file mode 100644
index 0000000000..f42477b97d
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/CallToNativeNode.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.common;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.InteropException;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray;
+import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray;
+import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+
+public abstract class CallToNativeNode extends Node {
+
+    @Child private Node message;
+    protected final NativeFunction function;
+
+    private CallToNativeNode(NativeFunction function) {
+        this.function = function;
+    }
+
+    public CallToNativeNode create(NativeFunction f) {
+        switch (RFFIFactory.getType()) {
+            case LLVM:
+                return new NFI(f);
+            case NFI:
+                return new LLVM(f);
+            default:
+                throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    protected abstract TruffleObject getTarget();
+
+    protected final Object call(Object... args) {
+        try {
+            if (message == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                message = insert(Message.createExecute(function.getArgumentCount()).createNode());
+            }
+            wrapArguments(args);
+            return ForeignAccess.sendExecute(message, getTarget(), args);
+        } catch (InteropException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        } finally {
+            finishArguments(args);
+        }
+    }
+
+    protected abstract void wrapArguments(Object[] args);
+
+    protected abstract void finishArguments(Object[] args);
+
+    private final class NFI extends CallToNativeNode {
+
+        private NFI(NativeFunction function) {
+            super(function);
+        }
+
+        @Override
+        protected TruffleObject getTarget() {
+            return function.getFunction();
+        }
+
+        @SuppressWarnings("cast")
+        @Override
+        @ExplodeLoop
+        protected void wrapArguments(Object[] args) {
+            for (int i = 0; i < args.length; i++) {
+                Object obj = args[i];
+                if (obj instanceof double[]) {
+                    args[i] = JavaInterop.asTruffleObject((double[]) obj);
+                } else if (obj instanceof int[] || obj == null) {
+                    args[i] = JavaInterop.asTruffleObject((int[]) obj);
+                }
+            }
+        }
+
+        @Override
+        @ExplodeLoop
+        protected void finishArguments(Object[] args) {
+            for (Object obj : args) {
+                if (obj instanceof NativeNACheck<?>) {
+                    ((NativeNACheck<?>) obj).close();
+                }
+            }
+        }
+    }
+
+    private final class LLVM extends CallToNativeNode {
+
+        @CompilationFinal private TruffleObject target;
+
+        private LLVM(NativeFunction function) {
+            super(function);
+        }
+
+        @Override
+        protected TruffleObject getTarget() {
+            if (target == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                target = DLL.findSymbol(function.getCallName(), null).asTruffleObject();
+            }
+            return target;
+        }
+
+        @Override
+        @ExplodeLoop
+        protected void wrapArguments(Object[] args) {
+            for (int i = 0; i < args.length; i++) {
+                Object obj = args[i];
+                if (obj instanceof double[]) {
+                    args[i] = new NativeDoubleArray((double[]) obj);
+                } else if (obj instanceof int[]) {
+                    args[i] = new NativeIntegerArray((int[]) obj);
+                } else if (obj == null) {
+                    args[i] = 0;
+                }
+            }
+        }
+
+        @Override
+        @ExplodeLoop
+        protected void finishArguments(Object[] args) {
+            for (Object obj : args) {
+                if (obj instanceof NativeNACheck<?>) {
+                    ((NativeNACheck<?>) obj).close();
+                }
+            }
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/DownCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/DownCallNode.java
index 95d2bbafb9..d4edf723b2 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/DownCallNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/DownCallNode.java
@@ -28,15 +28,16 @@ import com.oracle.truffle.api.interop.InteropException;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
 import com.oracle.truffle.r.runtime.RInternalError;
 
-public abstract class DownCallNode<T extends NativeFunction> extends Node {
+public abstract class DownCallNode extends Node {
 
     @Child private Node message;
 
     protected abstract TruffleObject getTarget();
 
-    protected abstract T getFunction();
+    protected abstract NativeFunction getFunction();
 
     protected final Object call(Object... args) {
         try {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index f31134fbfb..d442fd8196 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -104,6 +104,10 @@ 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.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.CEntry;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.gnur.SA_TYPE;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
@@ -681,7 +685,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     public Object TAG(Object e) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.TAG).call(e);
+        throw implementedAsNode();
     }
 
     @Override
@@ -1567,45 +1571,80 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         name2typeTable.put("name", SEXPTYPE.SYMSXP.code);
     }
 
+    @Override
+    public int registerRoutines(DLLInfo dllInfo, int nstOrd, int num, long routines) {
+        DotSymbol[] array = new DotSymbol[num];
+        for (int i = 0; i < num; i++) {
+            Object sym = setSymbol(dllInfo, nstOrd, routines, i);
+            array[i] = (DotSymbol) sym;
+        }
+        dllInfo.setNativeSymbols(nstOrd, array);
+        return 0;
+    }
+
+    @Override
+    public int registerCCallable(String pkgName, String functionName, Object address) {
+        DLLInfo lib = DLL.safeFindLibrary(pkgName);
+        lib.registerCEntry(new CEntry(functionName, new SymbolHandle(address)));
+        return 0;
+    }
+
+    @Override
+    public int useDynamicSymbols(DLLInfo dllInfo, int value) {
+        return DLL.useDynamicSymbols(dllInfo, value);
+    }
+
+    @Override
+    public int forceSymbols(DLLInfo dllInfo, int value) {
+        return DLL.forceSymbols(dllInfo, value);
+    }
+
+    @Override
+    public DotSymbol setDotSymbolValues(DLLInfo dllInfo, String name, Object fun, int numArgs) {
+        DotSymbol result = new DotSymbol(name, new SymbolHandle(fun), numArgs);
+        return result;
+    }
+
+    protected abstract Object setSymbol(DLLInfo dllInfo, int nstOrd, long routines, int index);
+
     @Override
     public double Rf_dunif(double a, double b, double c, int d) {
-        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_dunif).call(a, b, c, d);
+        throw implementedAsNode();
     }
 
     @Override
     public double Rf_qunif(double a, double b, double c, int d, int e) {
-        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_qunif).call(a, b, c, d, e);
+        throw implementedAsNode();
     }
 
     @Override
     public double Rf_punif(double a, double b, double c, int d, int e) {
-        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_punif).call(a, b, c, d, e);
+        throw implementedAsNode();
     }
 
     @Override
     public double Rf_runif(double a, double b) {
-        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_runif).call(a, b);
+        throw implementedAsNode();
     }
 
     @Override
     public Object Rf_namesgets(Object x, Object y) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_namesgets).call(x, y);
+        throw implementedAsNode();
     }
 
     @Override
     public int Rf_copyMostAttrib(Object x, Object y) {
-        FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_copyMostAttrib).call(x, y);
-        return 0;
+        throw implementedAsNode();
     }
 
     @Override
     public Object Rf_VectorToPairList(Object x) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_VectorToPairList).call(x);
+        throw implementedAsNode();
     }
 
     @Override
     public Object Rf_asCharacterFactor(Object x) {
-        return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_asCharacterFactor).call(x);
+        throw implementedAsNode();
     }
 
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/NativeFunction.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/NativeFunction.java
deleted file mode 100644
index dca5d7ddc7..0000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/NativeFunction.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.truffle.r.ffi.impl.common;
-
-public interface NativeFunction {
-
-    int getArgumentCount();
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNIUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNIUpCallsRFFIImpl.java
index 1c4911f127..8ee223bad4 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNIUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/jni/JNIUpCallsRFFIImpl.java
@@ -29,6 +29,7 @@ import com.oracle.truffle.r.runtime.RErrorHandling;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 
 /**
  * Some additional methods to support the native JNI side.
@@ -68,4 +69,14 @@ public class JNIUpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
     public Object R_CHAR(Object x) {
         throw RInternalError.shouldNotReachHere();
     }
+
+    @Override
+    public Object getCCallable(String pkgName, String functionName) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    protected Object setSymbol(DLLInfo dllInfo, int nstOrd, long routines, int index) {
+        throw RInternalError.shouldNotReachHere();
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/LLVMFunction.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/LLVMFunction.java
deleted file mode 100644
index 64a3482610..0000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/LLVMFunction.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.interop.Message;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.ffi.impl.common.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-
-/**
- * Enumerates all the C functions that are internal to the implementation and called via Truffle
- * LLVM. All of the functions are called indirectly via a wrapper, typically to enable a callback
- * with a complex result or, in the case of Fortran, to handle call by reference conveniently, or to
- * just have LLVM handle the underlying native call. The wrapper functions names are all of the form
- * {@code call_xxx_function}, where {@code xxx} is the subsystem.
- */
-public enum LLVMFunction implements NativeFunction {
-    // base
-    getpid(0, "call_base_"),
-    getwd(2, "call_base_"),
-    setwd(1, "call_base_"),
-    mkdir(2, "call_base_"),
-    readlink(2, "call_base_"),
-    mkdtemp(1, "call_base_"),
-    chmod(2, "call_base_"),
-    strtol(3, "call_base_"),
-    uname(1, "call_base_"),
-    glob(2, "call_base_"),
-    // PCRE
-    maketables(0, "call_pcre_"),
-    compile(4, "call_pcre_"),
-    getcapturecount(2, "call_pcre_"),
-    getcapturenames(3, "call_pcre_"),
-    study(2, "call_pcre_"),
-    exec(8, "call_pcre_"),
-    // RAppl
-    dqrdc2(9, "call_appl_"),
-    dqrcf(8, "call_appl_"),
-    dqrls(13, "call_appl_"),
-    // zip
-    compress(4, "call_zip_"),
-    uncompress(4, "call_zip_"),
-    // lapack
-    ilaver(1, "call_lapack_"),
-    dgeev(13, "call_lapack_"),
-    dgeqp3(8, "call_lapack_"),
-    dormq(12, "call_lapack_"),
-    dtrtrs(9, "call_lapack_"),
-    dgetrf(5, "call_lapack_"),
-    dpotrf(4, "call_lapack_"),
-    dpotri(4, "call_lapack_"),
-    dpstrf(9, "call_lapack_"),
-    dgesv(7, "call_lapack_"),
-    dlange(6, "call_lapack_"),
-    dgecon(8, "call_lapack_"),
-    dsyevr(20, "call_lapack_"),
-    // misc
-    exactSumFunc(4, "");
-
-    private final int argumentCount;
-    private final String callName;
-
-    LLVMFunction(int argCount, String prefix) {
-        this.argumentCount = argCount;
-        this.callName = prefix + name();
-    }
-
-    Node createMessage() {
-        CompilerAsserts.neverPartOfCompilation();
-        return Message.createExecute(argumentCount).createNode();
-    }
-
-    SymbolHandle createSymbol() {
-        return DLL.findSymbol(callName, null);
-    }
-
-    @Override
-    public int getArgumentCount() {
-        return argumentCount;
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
index f5edb934b7..3cd51bce2d 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
@@ -30,14 +30,15 @@ import com.oracle.truffle.r.ffi.impl.interop.base.GlobResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.ReadlinkResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.StrtolResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.UnameResult;
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 public class TruffleLLVM_Base implements BaseRFFI {
     private static final class TruffleLLVM_GetpidNode extends TruffleLLVM_DownCallNode implements GetpidNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.getpid;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getpid;
         }
 
         @Override
@@ -49,8 +50,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_GetwdNode extends TruffleLLVM_DownCallNode implements GetwdNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.getwd;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getcwd;
         }
 
         @Override
@@ -74,8 +75,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_SetwdNode extends TruffleLLVM_DownCallNode implements SetwdNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.setwd;
+        protected NativeFunction getFunction() {
+            return NativeFunction.chdir;
         }
 
         @Override
@@ -88,8 +89,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_MkdirNode extends TruffleLLVM_DownCallNode implements MkdirNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.mkdir;
+        protected NativeFunction getFunction() {
+            return NativeFunction.mkdir;
         }
 
         @Override
@@ -105,8 +106,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_ReadlinkNode extends TruffleLLVM_DownCallNode implements ReadlinkNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.readlink;
+        protected NativeFunction getFunction() {
+            return NativeFunction.readlink;
         }
 
         private static final int EINVAL = 22;
@@ -132,8 +133,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_MkdtempNode extends TruffleLLVM_DownCallNode implements MkdtempNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.mkdtemp;
+        protected NativeFunction getFunction() {
+            return NativeFunction.mkdtemp;
         }
 
         @Override
@@ -160,8 +161,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_ChmodNode extends TruffleLLVM_DownCallNode implements ChmodNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.chmod;
+        protected NativeFunction getFunction() {
+            return NativeFunction.chmod;
         }
 
         @Override
@@ -174,8 +175,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_StrolNode extends TruffleLLVM_DownCallNode implements StrolNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.strtol;
+        protected NativeFunction getFunction() {
+            return NativeFunction.strtol;
         }
 
         @Override
@@ -194,8 +195,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_UnameNode extends TruffleLLVM_DownCallNode implements UnameNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.uname;
+        protected NativeFunction getFunction() {
+            return NativeFunction.uname;
         }
 
         @Override
@@ -209,8 +210,8 @@ public class TruffleLLVM_Base implements BaseRFFI {
     private static class TruffleLLVM_GlobNode extends TruffleLLVM_DownCallNode implements GlobNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.glob;
+        protected NativeFunction getFunction() {
+            return NativeFunction.glob;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNode.java
index dc3b81c00c..34a74e3889 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNode.java
@@ -30,8 +30,9 @@ import com.oracle.truffle.r.ffi.impl.common.DownCallNode;
 import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray;
 import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray;
 import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
+import com.oracle.truffle.r.runtime.ffi.DLL;
 
-public abstract class TruffleLLVM_DownCallNode extends DownCallNode<LLVMFunction> {
+public abstract class TruffleLLVM_DownCallNode extends DownCallNode {
 
     @CompilationFinal private TruffleObject target;
 
@@ -39,7 +40,7 @@ public abstract class TruffleLLVM_DownCallNode extends DownCallNode<LLVMFunction
     protected final TruffleObject getTarget() {
         if (target == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            target = getFunction().createSymbol().asTruffleObject();
+            target = DLL.findSymbol(getFunction().getCallName(), null).asTruffleObject();
         }
         return target;
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java
index 0cc25fa7ab..7addd0fd6e 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.ffi.impl.llvm;
 
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.r.ffi.impl.common.LibPaths;
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
@@ -77,8 +78,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_IlaverNode extends TruffleLLVM_DownCallNode implements IlaverNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.ilaver;
+        protected NativeFunction getFunction() {
+            return NativeFunction.ilaver;
         }
 
         @Override
@@ -90,8 +91,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DgeevNode extends TruffleLLVM_DownCallNode implements DgeevNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dgeev;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgeev;
         }
 
         @Override
@@ -103,8 +104,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_Dgeqp3Node extends TruffleLLVM_DownCallNode implements Dgeqp3Node {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dgeqp3;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgeqp3;
         }
 
         @Override
@@ -116,8 +117,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DormqrNode extends TruffleLLVM_DownCallNode implements DormqrNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dormq;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dormq;
         }
 
         @Override
@@ -129,8 +130,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DtrtrsNode extends TruffleLLVM_DownCallNode implements DtrtrsNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dtrtrs;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dtrtrs;
         }
 
         @Override
@@ -142,8 +143,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DgetrfNode extends TruffleLLVM_DownCallNode implements DgetrfNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dgetrf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgetrf;
         }
 
         @Override
@@ -155,8 +156,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DpotrfNode extends TruffleLLVM_DownCallNode implements DpotrfNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dpotrf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dpotrf;
         }
 
         @Override
@@ -168,8 +169,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DpotriNode extends TruffleLLVM_DownCallNode implements DpotriNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dpotri;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dpotri;
         }
 
         @Override
@@ -181,8 +182,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DpstrfNode extends TruffleLLVM_DownCallNode implements DpstrfNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dpstrf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dpstrf;
         }
 
         @Override
@@ -194,8 +195,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DgesvNode extends TruffleLLVM_DownCallNode implements DgesvNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dgesv;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgesv;
         }
 
         @Override
@@ -207,8 +208,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DlangeNode extends TruffleLLVM_DownCallNode implements DlangeNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dlange;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dlange;
         }
 
         @Override
@@ -220,8 +221,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DgeconNode extends TruffleLLVM_DownCallNode implements DgeconNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dgecon;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgecon;
         }
 
         @Override
@@ -233,8 +234,8 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
     private static final class TruffleLLVM_DsyevrNode extends TruffleLLVM_DownCallNode implements DsyevrNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dsyevr;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dsyevr;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Misc.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Misc.java
index 40daead368..b37f1c2405 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Misc.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Misc.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.ffi.impl.llvm;
 
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
 import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 
 public class TruffleLLVM_Misc implements MiscRFFI {
@@ -29,8 +30,8 @@ public class TruffleLLVM_Misc implements MiscRFFI {
     private static class TruffleLLVM_ExactSumNode extends TruffleLLVM_DownCallNode implements ExactSumNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.exactSumFunc;
+        protected NativeFunction getFunction() {
+            return NativeFunction.exactSumFunc;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_PCRE.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_PCRE.java
index aad99cf04a..0cf905c387 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_PCRE.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_PCRE.java
@@ -29,6 +29,7 @@ import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray;
 import com.oracle.truffle.r.ffi.impl.interop.pcre.CaptureNamesResult;
 import com.oracle.truffle.r.ffi.impl.interop.pcre.CompileResult;
 import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_Utils.AsPointerNode;
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
@@ -46,8 +47,8 @@ public class TruffleLLVM_PCRE implements PCRERFFI {
         @Child private AsPointerNode asPointer = new AsPointerNode();
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.maketables;
+        protected NativeFunction getFunction() {
+            return NativeFunction.maketables;
         }
 
         @Override
@@ -58,8 +59,8 @@ public class TruffleLLVM_PCRE implements PCRERFFI {
 
     private static class TruffleLLVM_GetCaptureCountNode extends TruffleLLVM_DownCallNode implements GetCaptureCountNode {
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.getcapturecount;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getcapturecount;
         }
 
         @Override
@@ -70,8 +71,8 @@ public class TruffleLLVM_PCRE implements PCRERFFI {
 
     private static class TruffleLLVM_GetCaptureNamesNode extends TruffleLLVM_DownCallNode implements GetCaptureNamesNode {
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.getcapturenames;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getcapturenames;
         }
 
         @Override
@@ -89,8 +90,8 @@ public class TruffleLLVM_PCRE implements PCRERFFI {
 
     private static class TruffleLLVM_CompileNode extends TruffleLLVM_DownCallNode implements CompileNode {
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.compile;
+        protected NativeFunction getFunction() {
+            return NativeFunction.compile;
         }
 
         @Override
@@ -104,8 +105,8 @@ public class TruffleLLVM_PCRE implements PCRERFFI {
 
     private static class TruffleLLVM_ExecNode extends TruffleLLVM_DownCallNode implements ExecNode {
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.exec;
+        protected NativeFunction getFunction() {
+            return NativeFunction.exec;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RAppl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RAppl.java
index 1deb3356d3..a69785d17c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RAppl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RAppl.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.ffi.impl.llvm;
 
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.RApplRFFI;
 
@@ -33,8 +34,8 @@ public class TruffleLLVM_RAppl implements RApplRFFI {
     private static final class TruffleLLVM_Dqrdc2Node extends TruffleLLVM_DownCallNode implements Dqrdc2Node {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dqrdc2;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrdc2;
         }
 
         @Override
@@ -46,8 +47,8 @@ public class TruffleLLVM_RAppl implements RApplRFFI {
     private static final class TruffleLLVM_DqrcfNode extends TruffleLLVM_DownCallNode implements DqrcfNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dqrcf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrcf;
         }
 
         @Override
@@ -59,8 +60,8 @@ public class TruffleLLVM_RAppl implements RApplRFFI {
     private static final class TruffleLLVM_DqrlsNode extends TruffleLLVM_DownCallNode implements DqrlsNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.dqrls;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrls;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java
index bf236d54ec..db6c5f9183 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_RFFIContextState.java
@@ -63,9 +63,9 @@ class TruffleLLVM_RFFIContextState implements ContextState {
     }
 
     @Override
-    public void beforeDestroy(RContext context) {
-        dllState.beforeDestroy(context);
-        pkgInitState.beforeDestroy(context);
-        callState.beforeDestroy(context);
+    public void beforeDispose(RContext context) {
+        dllState.beforeDispose(context);
+        pkgInitState.beforeDispose(context);
+        callState.beforeDispose(context);
     }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
index bc64dc1163..83d886b44e 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
@@ -22,6 +22,11 @@
  */
 package com.oracle.truffle.r.ffi.impl.llvm;
 
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.InteropException;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.ffi.impl.common.JavaUpCallsRFFIImpl;
 import com.oracle.truffle.r.ffi.impl.common.RFFIUtils;
 import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray;
@@ -31,13 +36,19 @@ import com.oracle.truffle.r.ffi.impl.interop.NativeLogicalArray;
 import com.oracle.truffle.r.ffi.impl.interop.NativeRawArray;
 import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks;
 import com.oracle.truffle.r.runtime.REnvVars;
+import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RScalar;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.CEntry;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
 /**
  * (Incomplete) Variant of {@link JavaUpCallsRFFIImpl} for Truffle LLVM.
@@ -45,6 +56,12 @@ import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
  */
 public class TruffleLLVM_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
 
+    private static TruffleObject setSymbolHandle;
+
+    public TruffleLLVM_UpCallsRFFIImpl() {
+        setSymbolHandle = new SymbolHandle(RContext.getInstance().getEnv().importSymbol("@" + "Rdynload_setSymbol")).asTruffleObject();
+    }
+
     public Object charSXPToNativeCharArray(Object x) {
         CharSXPWrapper chars = RFFIUtils.guaranteeInstanceOf(x, CharSXPWrapper.class);
         return new NativeCharArray(chars.getContents().getBytes());
@@ -136,4 +153,24 @@ public class TruffleLLVM_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
     public Object getCallback(int index) {
         return Callbacks.values()[index].call;
     }
+
+    @Override
+    public Object getCCallable(String pkgName, String functionName) {
+        DLLInfo lib = DLL.safeFindLibrary(pkgName);
+        CEntry result = lib.lookupCEntry(functionName);
+        if (result == null) {
+            throw RError.error(RError.NO_CALLER, RError.Message.UNKNOWN_OBJECT, functionName);
+        }
+        return result.address.asTruffleObject();
+    }
+
+    @Override
+    protected Object setSymbol(DLLInfo dllInfo, int nstOrd, long routines, int index) {
+        Node executeNode = Message.createExecute(4).createNode();
+        try {
+            return ForeignAccess.sendExecute(executeNode, setSymbolHandle, dllInfo, nstOrd, routines, index);
+        } catch (InteropException ex) {
+            throw RInternalError.shouldNotReachHere(ex);
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Zip.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Zip.java
index f414a62339..5b9aa1c2b1 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Zip.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Zip.java
@@ -23,14 +23,15 @@
 package com.oracle.truffle.r.ffi.impl.llvm;
 
 import com.oracle.truffle.r.ffi.impl.interop.NativeRawArray;
+import com.oracle.truffle.r.ffi.impl.nfi.NativeFunction;
 import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
 
 public class TruffleLLVM_Zip implements ZipRFFI {
     private static class TruffleLLVM_CompressNode extends TruffleLLVM_DownCallNode implements CompressNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.compress;
+        protected NativeFunction getFunction() {
+            return NativeFunction.compress;
         }
 
         @Override
@@ -48,8 +49,8 @@ public class TruffleLLVM_Zip implements ZipRFFI {
     private static class TruffleLLVM_UncompressNode extends TruffleLLVM_DownCallNode implements UncompressNode {
 
         @Override
-        protected LLVMFunction getFunction() {
-            return LLVMFunction.uncompress;
+        protected NativeFunction getFunction() {
+            return NativeFunction.uncompress;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIFunction.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NativeFunction.java
similarity index 77%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIFunction.java
rename to com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NativeFunction.java
index 90562d62fc..9c7d350668 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NFIFunction.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/NativeFunction.java
@@ -24,13 +24,9 @@ package com.oracle.truffle.r.ffi.impl.nfi;
 
 import java.util.function.BiFunction;
 
-import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.ffi.impl.common.NativeFunction;
 
 /**
  * Enumerates all the C functions that are internal to the implementation and called via Truffle
@@ -38,27 +34,26 @@ import com.oracle.truffle.r.ffi.impl.common.NativeFunction;
  * enable a callback with a complex result or, in the case of Fortran, to handle call by reference
  * conveniently. The wrapper functions names are all of the form {@code call_xxx_function}, where
  * {@code xxx} is the subsystem.
- *
  */
-enum NFIFunction implements NativeFunction {
+public enum NativeFunction {
     // base
-    getpid("(): sint32"),
-    getcwd("([uint8], sint32): sint32"),
-    chdir("(string): sint32"),
-    mkdir("(string, sint32): sint32"),
+    getpid("(): sint32", "call_base_"),
+    getcwd("([uint8], sint32): sint32", "call_base_"),
+    chdir("(string): sint32", "call_base_"),
+    mkdir("(string, sint32): sint32", "call_base_"),
     readlink("((string, sint32): void, string): void", "call_base_"),
-    mkdtemp("([uint8]): sint32"),
-    chmod("(string, sint32): sint32"),
+    mkdtemp("([uint8]): sint32", "call_base_"),
+    chmod("(string, sint32): sint32", "call_base_"),
     strtol("((sint64, sint32): void, string, sint32): void", "call_base_"),
     uname("((string, string, string, string, string): void): void", "call_base_"),
     glob("((string): void, string): void", "call_base_"),
-    // PCRE, N.B. The "pcre_" prefixes are actually direct calls
-    maketables("(): sint64", "pcre_"),
+    // PCRE
+    maketables("(): sint64", "call_pcre_"),
     compile("((uint64, string, sint32): void, string, sint32, uint64): void", "call_pcre_"),
     getcapturecount("(uint64, uint64): sint32", "call_pcre_"),
     getcapturenames("((sint32, string): void, uint64, uint64): sint32", "call_pcre_"),
     study("(uint64, sint32): void", "call_pcre_"),
-    exec("(uint64, uint64, [uint8], sint32, sint32, sint32, [sint32], sint32): sint32", "pcre_"),
+    exec("(uint64, uint64, [uint8], sint32, sint32, sint32, [sint32], sint32): sint32", "call_pcre_"),
     // RAppl
     dqrdc2("([double], sint32, sint32, sint32, double, [sint32], [double], [sint32], [double]): void", "call_appl_"),
     dqrcf("([double], sint32, sint32, [double], [double], sint32, [double], [sint32]): void", "call_appl_"),
@@ -68,8 +63,8 @@ enum NFIFunction implements NativeFunction {
     dqrrsd("([double], sint32, sint32, [double], [double], sint32, [double]): void", "call_appl_"),
     dqrxb("([double], sint32, sint32, [double], [double], sint32, [double]): void", "call_appl_"),
     // zip
-    compress("([uint8], [uint64], [uint8], uint64): sint32"),
-    uncompress("([uint8], [uint64], [uint8], uint64): sint32"),
+    compress("([uint8], uint64, [uint8], uint64): sint32", "call_zip_"),
+    uncompress("([uint8], uint64, [uint8], uint64): sint32", "call_zip_"),
     // lapack
     ilaver("([sint32]): void", "call_lapack_"),
     dgeev("(uint8, uint8, sint32, [double], sint32, [double], [double], [double], sint32, [double], sint32, [double], sint32) : sint32", "call_lapack_"),
@@ -83,10 +78,11 @@ enum NFIFunction implements NativeFunction {
     dgesv("(sint32, sint32, [double], sint32, [sint32], [double], sint32) : sint32", "call_lapack_"),
     dlange("(uint8, sint32, sint32, [double], sint32, [double]) : double", "call_lapack_"),
     dgecon("(uint8, sint32, [double], sint32, double, [double], [double], [sint32]) : sint32", "call_lapack_"),
-    dsyevr("(uint8, uint8, uint8, sint32, [double], sint32, double, double, sint32, sint32, double, [sint32], [double], [double], sint32, [sint32], [double], sint32, " +
-                    "[sint32], sint32) : sint32", "call_lapack_"),
+    dsyevr(
+                    "(uint8, uint8, uint8, sint32, [double], sint32, double, double, sint32, sint32, double, [sint32], [double], [double], sint32, [sint32], [double], sint32, [sint32], sint32) : sint32",
+                    "call_lapack_"),
     // misc
-    exactSumFunc("([double], sint32, sint32, sint32): double"),
+    exactSumFunc("([double], sint32, sint32, sint32): double", "call_misc_"),
     // stats
     fft_factor("(sint32, [sint32], [sint32]): void", TruffleNFI_Utils::lookupAndBindStats),
     fft_work("([double], sint32, sint32, sint32, sint32, [double], [sint32]): sint32", TruffleNFI_Utils::lookupAndBindStats);
@@ -97,41 +93,33 @@ enum NFIFunction implements NativeFunction {
     private final BiFunction<String, String, TruffleObject> lookup;
     @CompilationFinal private TruffleObject function;
 
-    NFIFunction(String signature) {
-        this.argumentCount = TruffleNFI_Utils.getArgCount(signature);
-        this.signature = signature;
-        this.callName = name();
-        this.lookup = TruffleNFI_Utils::lookupAndBind;
-    }
-
-    NFIFunction(String signature, BiFunction<String, String, TruffleObject> lookup) {
+    NativeFunction(String signature, BiFunction<String, String, TruffleObject> lookup) {
         this.argumentCount = TruffleNFI_Utils.getArgCount(signature);
         this.signature = signature;
         this.callName = name();
         this.lookup = lookup;
     }
 
-    NFIFunction(String signature, String prefix) {
+    NativeFunction(String signature, String prefix) {
         this.argumentCount = TruffleNFI_Utils.getArgCount(signature);
         this.signature = signature;
         this.callName = prefix + name();
         this.lookup = TruffleNFI_Utils::lookupAndBind;
     }
 
-    Node createMessage() {
-        CompilerAsserts.neverPartOfCompilation();
-        return Message.createExecute(argumentCount).createNode();
+    public String getCallName() {
+        return callName;
     }
 
-    TruffleObject getFunction() {
+    public TruffleObject getFunction() {
         if (function == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             function = lookup.apply(callName, signature);
+            System.out.println("lookup " + callName);
         }
         return function;
     }
 
-    @Override
     public int getArgumentCount() {
         return argumentCount;
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
index eb2cb9fa87..c38173bfd4 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
@@ -38,8 +38,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_GetpidNode extends TruffleNFI_DownCallNode implements GetpidNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.getpid;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getpid;
         }
 
         @Override
@@ -51,8 +51,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static final class TruffleNFI_GetwdNode extends TruffleNFI_DownCallNode implements GetwdNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.getcwd;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getcwd;
         }
 
         @TruffleBoundary
@@ -75,8 +75,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_SetwdNode extends TruffleNFI_DownCallNode implements SetwdNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.chdir;
+        protected NativeFunction getFunction() {
+            return NativeFunction.chdir;
         }
 
         @Override
@@ -88,8 +88,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_MkdirNode extends TruffleNFI_DownCallNode implements MkdirNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.mkdir;
+        protected NativeFunction getFunction() {
+            return NativeFunction.mkdir;
         }
 
         @Override
@@ -104,8 +104,8 @@ public class TruffleNFI_Base implements BaseRFFI {
         private static final int EINVAL = 22;
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.readlink;
+        protected NativeFunction getFunction() {
+            return NativeFunction.readlink;
         }
 
         @Override
@@ -127,8 +127,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_MkdtempNode extends TruffleNFI_DownCallNode implements MkdtempNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.mkdtemp;
+        protected NativeFunction getFunction() {
+            return NativeFunction.mkdtemp;
         }
 
         @TruffleBoundary
@@ -154,8 +154,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_ChmodNode extends TruffleNFI_DownCallNode implements ChmodNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.chmod;
+        protected NativeFunction getFunction() {
+            return NativeFunction.chmod;
         }
 
         @Override
@@ -167,8 +167,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_StrolNode extends TruffleNFI_DownCallNode implements StrolNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.strtol;
+        protected NativeFunction getFunction() {
+            return NativeFunction.strtol;
         }
 
         @Override
@@ -186,8 +186,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_UnameNode extends TruffleNFI_DownCallNode implements UnameNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.uname;
+        protected NativeFunction getFunction() {
+            return NativeFunction.uname;
         }
 
         @Override
@@ -201,8 +201,8 @@ public class TruffleNFI_Base implements BaseRFFI {
     private static class TruffleNFI_GlobNode extends TruffleNFI_DownCallNode implements GlobNode {
 
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.glob;
+        protected NativeFunction getFunction() {
+            return NativeFunction.glob;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
index 0bcce8f8e3..4659744881 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
@@ -249,9 +249,10 @@ public class TruffleNFI_Call implements CallRFFI {
             if (arity >= SIGNATURES.length || SIGNATURES[arity] == null) {
                 StringBuilder str = new StringBuilder().append('(');
                 for (int i = 0; i < arity; i++) {
-                    str.append(i > 0 ? ", object" : "object");
+                    str.append(i > 0 ? ", " : "");
+                    str.append("pointer");
                 }
-                str.append("): object");
+                str.append("): pointer");
                 signature = str.toString();
                 if (arity < SIGNATURES.length) {
                     SIGNATURES[arity] = signature;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNode.java
index 49cbaf030a..f6f22e333d 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNode.java
@@ -28,7 +28,7 @@ import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.r.ffi.impl.common.DownCallNode;
 import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
 
-public abstract class TruffleNFI_DownCallNode extends DownCallNode<NFIFunction> {
+public abstract class TruffleNFI_DownCallNode extends DownCallNode {
 
     @Override
     protected final TruffleObject getTarget() {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Lapack.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Lapack.java
index af4e79315c..a69c62dcb4 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Lapack.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Lapack.java
@@ -28,8 +28,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_IlaverNode extends TruffleNFI_DownCallNode implements IlaverNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.ilaver;
+        protected NativeFunction getFunction() {
+            return NativeFunction.ilaver;
         }
 
         @Override
@@ -40,8 +40,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DgeevNode extends TruffleNFI_DownCallNode implements DgeevNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dgeev;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgeev;
         }
 
         @Override
@@ -52,8 +52,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_Dgeqp3Node extends TruffleNFI_DownCallNode implements Dgeqp3Node {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dgeqp3;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgeqp3;
         }
 
         @Override
@@ -64,8 +64,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DormqrNode extends TruffleNFI_DownCallNode implements DormqrNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dormq;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dormq;
         }
 
         @Override
@@ -76,8 +76,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DtrtrsNode extends TruffleNFI_DownCallNode implements DtrtrsNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dtrtrs;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dtrtrs;
         }
 
         @Override
@@ -88,8 +88,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DgetrfNode extends TruffleNFI_DownCallNode implements DgetrfNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dgetrf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgetrf;
         }
 
         @Override
@@ -100,8 +100,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DpotrfNode extends TruffleNFI_DownCallNode implements DpotrfNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dpotrf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dpotrf;
         }
 
         @Override
@@ -112,8 +112,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DpotriNode extends TruffleNFI_DownCallNode implements DpotriNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dpotri;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dpotri;
         }
 
         @Override
@@ -124,8 +124,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DpstrfNode extends TruffleNFI_DownCallNode implements DpstrfNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dpstrf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dpstrf;
         }
 
         @Override
@@ -136,8 +136,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DgesvNode extends TruffleNFI_DownCallNode implements DgesvNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dgesv;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgesv;
         }
 
         @Override
@@ -148,8 +148,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DlangeNode extends TruffleNFI_DownCallNode implements DlangeNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dlange;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dlange;
         }
 
         @Override
@@ -160,8 +160,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DgeconNode extends TruffleNFI_DownCallNode implements DgeconNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dgecon;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dgecon;
         }
 
         @Override
@@ -172,8 +172,8 @@ public class TruffleNFI_Lapack implements LapackRFFI {
 
     private static class TruffleNFI_DsyevrNode extends TruffleNFI_DownCallNode implements DsyevrNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dsyevr;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dsyevr;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Misc.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Misc.java
index 80503d78cb..9842145846 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Misc.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Misc.java
@@ -28,8 +28,8 @@ public class TruffleNFI_Misc implements MiscRFFI {
 
     private static final class TruffleNFI_ExactSumNode extends TruffleNFI_DownCallNode implements ExactSumNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.exactSumFunc;
+        protected NativeFunction getFunction() {
+            return NativeFunction.exactSumFunc;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PCRE.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PCRE.java
index 8a8326f9d4..dd525a3743 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PCRE.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PCRE.java
@@ -36,8 +36,8 @@ public class TruffleNFI_PCRE implements PCRERFFI {
 
     private static class TruffleNFI_MaketablesNode extends TruffleNFI_DownCallNode implements MaketablesNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.maketables;
+        protected NativeFunction getFunction() {
+            return NativeFunction.maketables;
         }
 
         @Override
@@ -48,8 +48,8 @@ public class TruffleNFI_PCRE implements PCRERFFI {
 
     private static class TruffleNFI_GetCaptureCountNode extends TruffleNFI_DownCallNode implements GetCaptureCountNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.getcapturecount;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getcapturecount;
         }
 
         @Override
@@ -60,8 +60,8 @@ public class TruffleNFI_PCRE implements PCRERFFI {
 
     private static class TruffleNFI_GetCaptureNamesNode extends TruffleNFI_DownCallNode implements GetCaptureNamesNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.getcapturenames;
+        protected NativeFunction getFunction() {
+            return NativeFunction.getcapturenames;
         }
 
         @Override
@@ -79,8 +79,8 @@ public class TruffleNFI_PCRE implements PCRERFFI {
 
     private static class TruffleNFI_CompileNode extends TruffleNFI_DownCallNode implements CompileNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.compile;
+        protected NativeFunction getFunction() {
+            return NativeFunction.compile;
         }
 
         @Override
@@ -93,8 +93,8 @@ public class TruffleNFI_PCRE implements PCRERFFI {
 
     private static class TruffleNFI_ExecNode extends TruffleNFI_DownCallNode implements ExecNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.exec;
+        protected NativeFunction getFunction() {
+            return NativeFunction.exec;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PkgInit.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PkgInit.java
index e35a96709c..e0741ce947 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PkgInit.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PkgInit.java
@@ -65,7 +65,6 @@ public final class TruffleNFI_PkgInit extends Generic_PkgInit {
                     case setDotSymbolValues:
                         callbackObject = new SetDotSymbolValuesCall(trufflePkgInit);
                         break;
-
                     case useDynamicSymbols:
                         callbackObject = new UseDynamicSymbolsCall(trufflePkgInit);
                         break;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RAppl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RAppl.java
index 5210f3ec9d..9e1d662147 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RAppl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_RAppl.java
@@ -28,8 +28,8 @@ public class TruffleNFI_RAppl implements RApplRFFI {
 
     private static class TruffleNFI_Dqrdc2Node extends TruffleNFI_DownCallNode implements Dqrdc2Node {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dqrdc2;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrdc2;
         }
 
         @Override
@@ -40,8 +40,8 @@ public class TruffleNFI_RAppl implements RApplRFFI {
 
     private static class TruffleNFI_DqrcfNode extends TruffleNFI_DownCallNode implements DqrcfNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dqrcf;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrcf;
         }
 
         @Override
@@ -52,8 +52,8 @@ public class TruffleNFI_RAppl implements RApplRFFI {
 
     private static class TruffleNFI_DqrlsNode extends TruffleNFI_DownCallNode implements DqrlsNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dqrls;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrls;
         }
 
         @Override
@@ -64,8 +64,8 @@ public class TruffleNFI_RAppl implements RApplRFFI {
 
     private static class TruffleNFI_DqrqtyNode extends TruffleNFI_DownCallNode implements DqrqtyNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dqrqty;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrqty;
         }
 
         @Override
@@ -76,8 +76,8 @@ public class TruffleNFI_RAppl implements RApplRFFI {
 
     private static class TruffleNFI_DqrqyNode extends TruffleNFI_DownCallNode implements DqrqyNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dqrqy;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrqy;
         }
 
         @Override
@@ -88,8 +88,8 @@ public class TruffleNFI_RAppl implements RApplRFFI {
 
     private static class TruffleNFI_DqrrsdNode extends TruffleNFI_DownCallNode implements DqrrsdNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dqrrsd;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrrsd;
         }
 
         @Override
@@ -100,8 +100,8 @@ public class TruffleNFI_RAppl implements RApplRFFI {
 
     private static class TruffleNFI_DqrxbNode extends TruffleNFI_DownCallNode implements DqrxbNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.dqrxb;
+        protected NativeFunction getFunction() {
+            return NativeFunction.dqrxb;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Stats.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Stats.java
index 217fdeb530..8d5d4da661 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Stats.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Stats.java
@@ -28,8 +28,8 @@ public class TruffleNFI_Stats implements StatsRFFI {
 
     private static class TruffleNFI_FactorNode extends TruffleNFI_DownCallNode implements FactorNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.fft_factor;
+        protected NativeFunction getFunction() {
+            return NativeFunction.fft_factor;
         }
 
         @Override
@@ -40,8 +40,8 @@ public class TruffleNFI_Stats implements StatsRFFI {
 
     private static class TruffleNFI_WorkNode extends TruffleNFI_DownCallNode implements WorkNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.fft_work;
+        protected NativeFunction getFunction() {
+            return NativeFunction.fft_work;
         }
 
         @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
index 02cf2c4eaa..5729f86c9b 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java
@@ -22,11 +22,45 @@
  */
 package com.oracle.truffle.r.ffi.impl.nfi;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.InteropException;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.ffi.impl.common.JavaUpCallsRFFIImpl;
+import com.oracle.truffle.r.ffi.impl.common.PkgInitUpCalls;
+import com.oracle.truffle.r.ffi.impl.interop.pkginit.ForceSymbolsCall;
+import com.oracle.truffle.r.ffi.impl.interop.pkginit.GetCCallableCall;
+import com.oracle.truffle.r.ffi.impl.interop.pkginit.RegisterCCallableCall;
+import com.oracle.truffle.r.ffi.impl.interop.pkginit.RegisterRoutinesCall;
+import com.oracle.truffle.r.ffi.impl.interop.pkginit.SetDotSymbolValuesCall;
+import com.oracle.truffle.r.ffi.impl.interop.pkginit.UseDynamicSymbolsCall;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.CEntry;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
 public class TruffleNFI_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
+
+    private static final String SETSYMBOL_SIGNATURE = "(object, sint32, uint64, sint32): object";
+    private static TruffleObject setSymbolFunction;
+
+    public TruffleNFI_UpCallsRFFIImpl() {
+        Node bind = Message.createInvoke(1).createNode();
+        SymbolHandle symbolHandle = DLL.findSymbol("Rdynload_setSymbol", null);
+        try {
+            setSymbolFunction = (TruffleObject) ForeignAccess.sendInvoke(bind, symbolHandle.asTruffleObject(), "bind", SETSYMBOL_SIGNATURE);
+        } catch (InteropException ex) {
+            throw RInternalError.shouldNotReachHere(ex);
+        }
+    }
+
     @Override
     public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
         // "bytes" is actually a Long unboxed from a NativePointer
@@ -96,4 +130,25 @@ public class TruffleNFI_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
         }
         return x;
     }
+
+    @Override
+    @TruffleBoundary
+    public Object getCCallable(String pkgName, String functionName) {
+        DLLInfo lib = DLL.safeFindLibrary(pkgName);
+        CEntry result = lib.lookupCEntry(functionName);
+        if (result == null) {
+            throw RError.error(RError.NO_CALLER, RError.Message.UNKNOWN_OBJECT, functionName);
+        }
+        return result.address.asAddress();
+    }
+
+    @Override
+    protected DotSymbol setSymbol(DLLInfo dllInfo, int nstOrd, long routines, int index) {
+        Node executeNode = Message.createExecute(4).createNode();
+        try {
+            return (DotSymbol) ForeignAccess.sendExecute(executeNode, setSymbolFunction, dllInfo, nstOrd, routines, index);
+        } catch (InteropException ex) {
+            throw RInternalError.shouldNotReachHere(ex);
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Zip.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Zip.java
index fe6ff0492c..c6a622dc30 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Zip.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Zip.java
@@ -29,29 +29,25 @@ public class TruffleNFI_Zip implements ZipRFFI {
 
     private static class TruffleNFI_CompressNode extends TruffleNFI_DownCallNode implements ZipRFFI.CompressNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.compress;
+        protected NativeFunction getFunction() {
+            return NativeFunction.compress;
         }
 
         @Override
         public int execute(byte[] dest, byte[] source) {
-            long[] destlen = new long[]{dest.length};
-            int result = (int) call(JavaInterop.asTruffleObject(dest), JavaInterop.asTruffleObject(destlen), JavaInterop.asTruffleObject(source), source.length);
-            return result;
+            return (int) call(JavaInterop.asTruffleObject(dest), (long) dest.length, JavaInterop.asTruffleObject(source), source.length);
         }
     }
 
     private static class TruffleNFI_UncompressNode extends TruffleNFI_DownCallNode implements ZipRFFI.UncompressNode {
         @Override
-        protected NFIFunction getFunction() {
-            return NFIFunction.uncompress;
+        protected NativeFunction getFunction() {
+            return NativeFunction.uncompress;
         }
 
         @Override
         public int execute(byte[] dest, byte[] source) {
-            long[] destlen = new long[]{dest.length};
-            int result = (int) call(JavaInterop.asTruffleObject(dest), JavaInterop.asTruffleObject(destlen), JavaInterop.asTruffleObject(source), source.length);
-            return result;
+            return (int) call(JavaInterop.asTruffleObject(dest), (long) dest.length, JavaInterop.asTruffleObject(source), source.length);
         }
     }
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java
index 4927664418..8ab5b1bf94 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java
@@ -27,6 +27,9 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodesFactory.ATTRIBNodeGen;
+import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodesFactory.CopyMostAttribNodeGen;
+import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodesFactory.TAGNodeGen;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.GetAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
@@ -46,7 +49,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 
 public final class AttributesAccessNodes {
 
-    abstract static class ATTRIB extends FFIUpCallNode.Arg1 {
+    public abstract static class ATTRIB extends FFIUpCallNode.Arg1 {
         @Child private GetAttributesNode getAttributesNode;
 
         @Specialization
@@ -68,9 +71,13 @@ public final class AttributesAccessNodes {
                 throw RError.error(RError.NO_CALLER, Message.GENERIC, "object of type '" + type + "' cannot be attributed");
             }
         }
+
+        public static ATTRIB create() {
+            return ATTRIBNodeGen.create();
+        }
     }
 
-    abstract static class TAG extends FFIUpCallNode.Arg1 {
+    public abstract static class TAG extends FFIUpCallNode.Arg1 {
 
         @Specialization
         public Object doPairlist(RPairList obj) {
@@ -106,9 +113,13 @@ public final class AttributesAccessNodes {
         public RNull doOthers(Object obj) {
             throw RInternalError.unimplemented("TAG is not implemented for type " + obj.getClass().getSimpleName());
         }
+
+        public static TAG create() {
+            return TAGNodeGen.create();
+        }
     }
 
-    abstract static class CopyMostAttrib extends FFIUpCallNode.Arg2 {
+    public abstract static class CopyMostAttrib extends FFIUpCallNode.Arg2 {
 
         @Child protected CopyOfRegAttributesNode copyRegAttributes;
 
@@ -127,5 +138,9 @@ public final class AttributesAccessNodes {
         public Void doOthers(Object x, Object y) {
             throw RInternalError.unimplemented("Rf_copyMostAttrib only works with atrributables.");
         }
+
+        public static CopyMostAttrib create() {
+            return CopyMostAttribNodeGen.create();
+        }
     }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
index ad332c7065..aebfa378cd 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java
@@ -58,7 +58,7 @@ import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 
 public final class CoerceNodes {
 
-    abstract static class VectorToPairListNode extends FFIUpCallNode.Arg1 {
+    public abstract static class VectorToPairListNode extends FFIUpCallNode.Arg1 {
 
         @Child private CopyOfRegAttributesNode copyRegAttributesNode;
         @Child private GetNamesAttributeNode getNamesAttributeNode;
@@ -119,7 +119,7 @@ public final class CoerceNodes {
         }
     }
 
-    abstract static class AsCharacterFactor extends FFIUpCallNode.Arg1 {
+    public abstract static class AsCharacterFactor extends FFIUpCallNode.Arg1 {
 
         @Child private InheritsCheckNode inheritsFactorNode = InheritsCheckNode.createFactor();
         @Child private GetAttributeNode getAttributeNode = GetAttributeNode.create();
@@ -164,7 +164,7 @@ public final class CoerceNodes {
     /**
      * Implements Rf_coerceVector.
      */
-    abstract static class CoerceVectorNode extends FFIUpCallNode.Arg2 {
+    public abstract static class CoerceVectorNode extends FFIUpCallNode.Arg2 {
 
         public static CoerceVectorNode create() {
             return CoerceNodesFactory.CoerceVectorNodeGen.create();
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/DLLUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/DLLUpCallsRFFI.java
new file mode 100644
index 0000000000..f4964eb0d9
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/DLLUpCallsRFFI.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.upcalls;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+
+public interface DLLUpCallsRFFI {
+
+    /**
+     * This is the start, called from {@code R_RegisterRoutines}.
+     *
+     * @param dllInfo library the symbols are defined in
+     * @param nstOrd the ordinal value corresponding to
+     *            {@link com.oracle.truffle.r.runtime.ffi.DLL.NativeSymbolType}.
+     * @param num the number of functions being registered
+     * @param routines the C address of the function table (not interpreted).
+     */
+    int registerRoutines(DLLInfo dllInfo, int nstOrd, int num, long routines);
+
+    /**
+     * Internal upcall used by {@code Rdynload_setSymbol}. The {@code fun} value must be converted
+     * to a {@link TruffleObject} representing the symbol}.
+     *
+     * @param dllInfo library the symbol is defined in
+     * @param name name of function
+     * @param fun a representation of the the C address of the function (in the table)
+     * @param numArgs the number of arguments the function takes.
+     */
+    Object setDotSymbolValues(DLLInfo dllInfo, String name, Object fun, int numArgs);
+
+    /**
+     * Directly implements {@code R_useDynamicSymbols}.
+     */
+    int useDynamicSymbols(DLLInfo dllInfo, int value);
+
+    /**
+     * Directly implements {@code R_forceSymbols}.
+     */
+    int forceSymbols(DLLInfo dllInfo, int value);
+
+    /**
+     * Directly implements {@code R_RegisterCCallable}.
+     */
+    int registerCCallable(String pkgName, String functionName, Object fun);
+
+    /**
+     * Directly implements {@code R_GetCCallable}.
+     */
+    Object getCCallable(String pkgName, String functionName);
+
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
index 9b83b536d8..3bfb5ff467 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java
@@ -23,24 +23,26 @@
 package com.oracle.truffle.r.ffi.impl.upcalls;
 
 import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.UnsupportedMessageException;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.ffi.impl.interop.NativePointer;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.NativeDataAccess;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public final class FFIUnwrapNode extends Node {
 
+    @Child private Node isPointer;
+    @Child private Node asPointer;
+
     @Child private Node isBoxed;
     @Child private Node unbox;
 
-    private final BranchProfile nativePointerProfile = isLLVM() ? BranchProfile.create() : null;
+    private final BranchProfile isRTruffleObject = BranchProfile.create();
+    private final BranchProfile isNonBoxed = BranchProfile.create();
 
     /**
      * There are three possibilities as enumerated below.
@@ -58,14 +60,31 @@ public final class FFIUnwrapNode extends Node {
      */
     public Object execute(Object x) {
         if (x instanceof RTruffleObject) {
+            isRTruffleObject.enter();
             return x;
         } else if (x instanceof TruffleObject) {
-            if (isBoxed == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                isBoxed = insert(Message.IS_BOXED.createNode());
-            }
             TruffleObject xTo = (TruffleObject) x;
-            if (ForeignAccess.sendIsBoxed(isBoxed, xTo)) {
+            Node isPointerNode = isPointer;
+            if (isPointerNode == null || ForeignAccess.sendIsPointer(isPointerNode, xTo)) {
+                if (asPointer == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    asPointer = insert(Message.AS_POINTER.createNode());
+                }
+                try {
+                    long address = ForeignAccess.sendAsPointer(asPointer, xTo);
+                    return NativeDataAccess.lookup(address);
+                } catch (UnsupportedMessageException e) {
+                    if (isPointerNode == null) {
+                        // only create IS_POINTER if we've seen AS_POINTER failing
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        isPointer = insert(Message.IS_POINTER.createNode());
+                    } else {
+                        throw RInternalError.shouldNotReachHere(e);
+                    }
+                }
+            }
+            Node isBoxedNode = isBoxed;
+            if (isBoxedNode == null || ForeignAccess.sendIsBoxed(isBoxedNode, xTo)) {
                 if (unbox == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
                     unbox = insert(Message.UNBOX.createNode());
@@ -73,33 +92,22 @@ public final class FFIUnwrapNode extends Node {
                 try {
                     return ForeignAccess.sendUnbox(unbox, xTo);
                 } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere(e, "UNBOX message fails after IS_BOXED=true");
-                }
-            } else {
-                // didn't UNBOX or really was null (e.g. null String)
-                if (isLLVM()) {
-                    nativePointerProfile.enter();
-                    TruffleObject xtoObject = checkNativePointer(xTo);
-                    if (xtoObject != null) {
-                        return xtoObject;
+                    if (isBoxedNode == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        isBoxed = insert(Message.IS_BOXED.createNode());
+                    } else {
+                        throw RInternalError.shouldNotReachHere(e);
                     }
                 }
-                return x;
             }
-        } else {
+            isNonBoxed.enter();
             return x;
+        } else {
+            CompilerDirectives.transferToInterpreter();
+            throw RInternalError.shouldNotReachHere("unexpected primitive value of class " + x.getClass().getSimpleName());
         }
     }
 
-    private static boolean isLLVM() {
-        return RFFIFactory.getType() == RFFIFactory.Type.LLVM;
-    }
-
-    @TruffleBoundary
-    private static TruffleObject checkNativePointer(TruffleObject xto) {
-        return NativePointer.check(xto);
-    }
-
     public static FFIUnwrapNode create() {
         return new FFIUnwrapNode();
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
index 4f5e750db6..d32cf9f1a9 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
@@ -25,8 +25,14 @@ package com.oracle.truffle.r.ffi.impl.upcalls;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDouble;
+import com.oracle.truffle.r.runtime.data.RInteger;
+import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RObject;
+import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.RScalarList;
 
 public abstract class FFIWrapNode extends Node {
 
@@ -52,6 +58,36 @@ public abstract class FFIWrapNode extends Node {
         return wrap(RDataFactory.createStringVectorFromScalar(value));
     }
 
+    @Specialization
+    protected static Object wrap(RInteger value) {
+        return wrap(RDataFactory.createIntVectorFromScalar(value.getValue()));
+    }
+
+    @Specialization
+    protected static Object wrap(RDouble value) {
+        return wrap(RDataFactory.createDoubleVectorFromScalar(value.getValue()));
+    }
+
+    @Specialization
+    protected static Object wrap(RLogical value) {
+        return wrap(RDataFactory.createLogicalVectorFromScalar(value.getValue()));
+    }
+
+    @Specialization
+    protected static Object wrap(RRaw value) {
+        return wrap(RDataFactory.createRawVectorFromScalar(value));
+    }
+
+    @Specialization
+    protected static Object wrap(RScalarList value) {
+        return wrap(RDataFactory.createList(new Object[]{value.getValue()}));
+    }
+
+    @Specialization
+    protected static Object wrap(RComplex value) {
+        return wrap(RDataFactory.createComplexVectorFromScalar(value));
+    }
+
     @Specialization
     protected static Object wrap(RObject value) {
         return value;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
index 2b82ab0a17..c9ace1e634 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
@@ -22,12 +22,15 @@
  */
 package com.oracle.truffle.r.ffi.impl.upcalls;
 
-import com.oracle.truffle.r.ffi.impl.nodes.ATTRIB;
 import com.oracle.truffle.r.ffi.impl.nodes.AsCharNode;
 import com.oracle.truffle.r.ffi.impl.nodes.AsIntegerNode;
 import com.oracle.truffle.r.ffi.impl.nodes.AsLogicalNode;
 import com.oracle.truffle.r.ffi.impl.nodes.AsRealNode;
-import com.oracle.truffle.r.ffi.impl.nodes.CoerceVectorNode;
+import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodes.ATTRIB;
+import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodes.CopyMostAttrib;
+import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodes.TAG;
+import com.oracle.truffle.r.ffi.impl.nodes.CoerceNodes.CoerceVectorNode;
+import com.oracle.truffle.r.ffi.impl.nodes.CoerceNodes.VectorToPairListNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CADDRNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CADRNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CARNode;
@@ -175,6 +178,7 @@ public interface StdUpCallsRFFI {
 
     Object PRINTNAME(Object x);
 
+    @RFFIUpCallNode(TAG.class)
     Object TAG(Object e);
 
     @RFFIUpCallNode(CARNode.class)
@@ -323,9 +327,12 @@ public interface StdUpCallsRFFI {
 
     Object Rf_namesgets(Object vec, Object val);
 
+    @RFFIUpCallNode(CopyMostAttrib.class)
     int Rf_copyMostAttrib(Object x, Object y);
 
+    @RFFIUpCallNode(VectorToPairListNode.class)
     Object Rf_VectorToPairList(Object x);
 
+    @RFFIUpCallNode(CADDRNode.class)
     Object Rf_asCharacterFactor(Object x);
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/UpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/UpCallsRFFI.java
index 9d47187191..19b16e4461 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/UpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/UpCallsRFFI.java
@@ -28,6 +28,6 @@ import com.oracle.truffle.r.ffi.processor.RFFIUpCallRoot;
  * Aggregation of all the FFI upcall interfaces.
  */
 @RFFIUpCallRoot
-public interface UpCallsRFFI extends StdUpCallsRFFI, IDEUpCallsRFFI, VariableUpCallsRFFI {
+public interface UpCallsRFFI extends StdUpCallsRFFI, IDEUpCallsRFFI, VariableUpCallsRFFI, DLLUpCallsRFFI {
 
 }
diff --git a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
index d3e84a3759..4ca6eef9c4 100644
--- a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
+++ b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
@@ -374,7 +374,7 @@ public final class FFIProcessor extends AbstractProcessor {
         switch (paramTypeName) {
             case "java.lang.Object":
                 if (rffiCstring == null) {
-                    return "object";
+                    return "pointer";
                 } else {
                     return rffiCstring.convert() ? "string" : "pointer";
                 }
@@ -405,7 +405,7 @@ public final class FFIProcessor extends AbstractProcessor {
                 } else {
                     processingEnv.getMessager().printMessage(Kind.ERROR, "Invalid parameter type " + paramTypeName, m);
                 }
-                return "object";
+                return "pointer";
         }
     }
 
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
similarity index 81%
rename from com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.h
rename to com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
index 72cd777fbc..25215c77f1 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
@@ -29,6 +29,39 @@
 #include <sys/utsname.h>
 #include <errno.h>
 
+int call_base_getpid() {
+    return getpid();
+}
+
+int call_base_getcwd(char *buf, int len) {
+    char *r = getcwd(buf, len);
+    if (r == NULL) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+int call_base_chdir(char *dir) {
+    return chdir(dir);
+}
+
+int call_base_mkdir(char *dir, int mode) {
+    return mkdir(dir, mode);
+}
+
+int call_base_mkdtemp(char *template) {
+    char *r = mkdtemp(template);
+    if (r == NULL) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+int call_base_chmod(char *path, int mode) {
+    return chmod(path, mode);
+}
 
 void call_base_uname(void (*call_uname_setfields)(char *sysname, char *release, char *version, char *machine, char *nodename)) {
 	struct utsname name;
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/lapack_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/lapack_rffi.c
index e543efacf8..ad968f4e0e 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/lapack_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/lapack_rffi.c
@@ -62,7 +62,6 @@ int call_lapack_dormqr(char side, char trans, int m, int n, int k, double *a, in
 
 extern int dtrtrs_(char *uplo, char *trans, char *diag, int *n, int *nrhs, double *a, int *lda, double *b, int *ldb, int *info);
 
-
 int call_lapack_dtrtrs(char uplo, char trans, char diag, int n, int nrhs, double *a, int lda, double *b, int ldb) {
     int info;
     dtrtrs_(&uplo, &trans, &diag, &n, &nrhs, a, &lda, b, &ldb, &info);
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/misc_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/misc_rffi.c
index f5ccdf078a..924c54ff2a 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/misc_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/misc_rffi.c
@@ -23,7 +23,7 @@
 
 #include <rffiutils.h>
 
-double exactSumFunc(double* contents, int length, int hasNa, int naRm) {
+double call_misc_exactSumFunc(double* contents, int length, int hasNa, int naRm) {
 
 	long double sum = 0;
 	int i = 0;
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/pcre_rffi.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/pcre_rffi.c
similarity index 87%
rename from com.oracle.truffle.r.native/fficall/src/truffle_common/pcre_rffi.h
rename to com.oracle.truffle.r.native/fficall/src/truffle_common/pcre_rffi.c
index 0b20885465..f70dca58ca 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/pcre_rffi.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/pcre_rffi.c
@@ -30,9 +30,13 @@
 extern char *pcre_maketables();
 extern void *pcre_compile(char *pattern, int options, char **errorMessage, int *errOffset, char *tables);
 extern int  pcre_exec(void *code, void *extra, char* subject, int subjectLength, int startOffset, int options, int *ovector, int ovecSize);
-int pcre_fullinfo(void *code, void *extra, int what, void *where);
+extern int pcre_fullinfo(void *code, void *extra, int what, void *where);
 extern void pcre_free(void *code);
 
+char *call_pcre_maketables() {
+    return pcre_maketables();
+}
+
 void call_pcre_compile(void (*makeresult)(long result, char *errMsg, int errOffset), char *pattern, int options, long tables) {
 	char *errorMessage;
 	int errOffset;
@@ -43,6 +47,10 @@ void call_pcre_compile(void (*makeresult)(long result, char *errMsg, int errOffs
 	}	makeresult((long) pcre_result, msg, errOffset);
 }
 
+int call_pcre_exec(long code, long extra, char *subject, int subjectLength, int startOffset, int options, int *ovectorElems, int ovectorLen) {
+    return pcre_exec((void *) code, (void *) extra, (char *) subject, subjectLength, startOffset, options, ovectorElems, ovectorLen);
+}
+
 int call_pcre_getcapturecount(long code, long extra) {
     int captureCount;
 	int rc = pcre_fullinfo((void*) code, (void*) extra, PCRE_INFO_CAPTURECOUNT, &captureCount);
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/zip_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/zip_rffi.c
similarity index 87%
rename from com.oracle.truffle.r.native/fficall/src/truffle_llvm/zip_rffi.c
rename to com.oracle.truffle.r.native/fficall/src/truffle_common/zip_rffi.c
index 026aff63a0..fb593da1d9 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/zip_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/zip_rffi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,9 @@ extern int compress(char *dest, long *destlen, char *source, long sourcelen);
 extern int uncompress(char *dest, long *destlen, char *source, long sourcelen);
 
 int call_zip_compress(char *dest, long destlen, char *source, long sourcelen) {
-	return compress(dest, &destlen, source, sourcelen);
+    return compress(dest, &destlen, source, sourcelen);
 }
 
 int call_zip_uncompress(char *dest, long destlen, char *source, long sourcelen) {
-	return uncompress(dest, &destlen, source, sourcelen);
+    return uncompress(dest, &destlen, source, sourcelen);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/base_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/base_rffi.c
deleted file mode 100644
index 78d7aaddeb..0000000000
--- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/base_rffi.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-#include <rffiutils.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <glob.h>
-#include <sys/utsname.h>
-#include <errno.h>
-#include <rffiutils.h>
-
-#include "../truffle_common/base_rffi.h"
-
-int call_base_getpid() {
-	return getpid();
-}
-
-int call_base_getwd(char *buf, int len) {
-	char *r = getcwd(buf, len);
-	if (r == NULL) {
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-int call_base_setwd(char *dir) {
-	return chdir(dir);
-}
-
-int call_base_mkdir(char *dir, int mode) {
-	return mkdir(dir, mode);
-}
-
-int call_base_mkdtemp(char *template) {
-	char *r = mkdtemp(template);
-	if (r == NULL) {
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-
-int call_base_chmod(char *path, int mode) {
-	int rc = chmod(path, mode);
-	return rc;
-}
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/pcre_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/pcre_rffi.c
deleted file mode 100644
index 170bfeaeeb..0000000000
--- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/pcre_rffi.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
- * Copyright (c) 1997-2015,  The R Core Team
- * Copyright (c) 2017, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-#include <rffiutils.h>
-
-#include "../truffle_common/pcre_rffi.h"
-
-char *call_pcre_maketables() {
-	return pcre_maketables();
-}
-
-int call_pcre_exec(long code, long extra, char *subject, int subjectLength, int startOffset, int options, int *ovectorElems, int ovectorLen) {
-	int rc = pcre_exec((void *) code, (void *) extra, (char *) subject, subjectLength, startOffset, options,
-			ovectorElems, ovectorLen);
-	return rc;
-}
-
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/base_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/base_rffi.c
deleted file mode 100644
index 8d35f6e2cd..0000000000
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/base_rffi.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-#include <rffiutils.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <glob.h>
-#include <sys/utsname.h>
-#include <errno.h>
-#include <rffiutils.h>
-
-#include "../truffle_common/base_rffi.h"
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/pcre_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/pcre_rffi.c
deleted file mode 100644
index 0a4acc6f2d..0000000000
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/pcre_rffi.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
- * Copyright (c) 1997-2015,  The R Core Team
- * Copyright (c) 2017, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-
-#include "../truffle_common/pcre_rffi.h"
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java
index 3c67535693..c48a542d24 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java
@@ -75,7 +75,7 @@ public class TempPathName implements RContext.ContextState {
 
     @Override
     @TruffleBoundary
-    public void beforeDestroy(RContext context) {
+    public void beforeDispose(RContext context) {
         if (context.getKind() == RContext.ContextKind.SHARE_PARENT_RW) {
             return;
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java
index 825aa4cd44..8cfbfa11a8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java
@@ -152,7 +152,7 @@ public class ConnectionSupport {
         }
 
         @Override
-        public void beforeDestroy(RContext context) {
+        public void beforeDispose(RContext context) {
             // close all open connections
             for (int i = 3; i <= hwm; i++) {
                 WeakReference<BaseRConnection> ref = allConnections.get(i);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index e229eb4c45..dba46132d7 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -192,10 +192,10 @@ public final class RContext implements RTruffleObject {
          */
         ACTIVE,
         /**
-         * The {@link RContext} object has been destroyed by the {@link #destroy} method. All
+         * The {@link RContext} object has been destroyed by the {@link #dispose} method. All
          * subsequent operations ideally should throw {@link IllegalStateException}.
          */
-        DESTROYED
+        DISPOSED
     }
 
     /**
@@ -214,11 +214,11 @@ public final class RContext implements RTruffleObject {
         }
 
         /**
-         * Called in response to the {@link RContext#destroy} method. Provides a hook for finalizing
+         * Called in response to the {@link RContext#dispose} method. Provides a hook for finalizing
          * any state before the context is destroyed.
          */
         @SuppressWarnings("unused")
-        default void beforeDestroy(RContext context) {
+        default void beforeDispose(RContext context) {
             // default empty implementation
         }
     }
@@ -563,17 +563,17 @@ public final class RContext implements RTruffleObject {
     /**
      * Destroy this context.
      */
-    public synchronized void destroy() {
-        if (!state.contains(State.DESTROYED)) {
+    public synchronized void dispose() {
+        if (!state.contains(State.DISPOSED)) {
             if (state.contains(State.INITIALIZED)) {
                 for (ContextState contextState : contextStates()) {
-                    contextState.beforeDestroy(this);
+                    contextState.beforeDispose(this);
                 }
             }
             if (contextKind == ContextKind.SHARE_PARENT_RW) {
                 parentContext.sharedChild = null;
             }
-            state = EnumSet.of(State.DESTROYED);
+            state = EnumSet.of(State.DISPOSED);
 
             this.allocationReporter.removePropertyChangeListener(ALLOCATION_ACTIVATION_LISTENER);
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java
index 32aa23a769..16941c5fba 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java
@@ -36,8 +36,9 @@ public interface RForeignAccessFactory {
      * Changes the interpretation of {@RNull} as {@code null} to {@code value}. This allows the
      * {@code FFI} implementations to prevent {@RNull} being converted across the {@code FFI}
      * interface, which would be incorrect.
-     *
+     * 
      * @return the previous setting
      */
     boolean setIsNull(boolean value);
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
new file mode 100644
index 0000000000..a05f4130f9
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.data;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+
+import sun.misc.Unsafe;
+
+abstract class InteropRootNode extends RootNode {
+    InteropRootNode() {
+        super(RContext.getInstance().getLanguage());
+    }
+
+    @Override
+    public final SourceSection getSourceSection() {
+        return RSyntaxNode.INTERNAL;
+    }
+}
+
+class UnsafeAdapter {
+    public static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+}
+
+public final class NativeDataAccess {
+    private NativeDataAccess() {
+        // no instances
+    }
+
+    private static final class NativeMirror {
+        private final long id;
+        private long dataAddress;
+
+        NativeMirror() {
+            this.id = counter.incrementAndGet();
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            super.finalize();
+            nativeMirrors.remove(id);
+            if (dataAddress != 0) {
+                UnsafeAdapter.UNSAFE.freeMemory(dataAddress);
+                assert (dataAddress = 0xbadbad) != 0;
+            }
+        }
+    }
+
+    private static final AtomicLong counter = new AtomicLong(0xdef000000000000L);
+    private static final ConcurrentHashMap<Long, WeakReference<RObject>> nativeMirrors = new ConcurrentHashMap<>();
+
+    public static CallTarget createIsPointer() {
+        return Truffle.getRuntime().createCallTarget(new InteropRootNode() {
+            @Override
+            public Object execute(VirtualFrame frame) {
+                return ForeignAccess.getReceiver(frame) instanceof RObject;
+            }
+        });
+    }
+
+    public static CallTarget createAsPointer() {
+        return Truffle.getRuntime().createCallTarget(new InteropRootNode() {
+            @Override
+            public Object execute(VirtualFrame frame) {
+                Object arg = ForeignAccess.getReceiver(frame);
+                if (arg instanceof RObject) {
+                    RObject obj = (RObject) arg;
+                    NativeMirror mirror = (NativeMirror) obj.getNativeMirror();
+                    if (mirror == null) {
+                        obj.setNativeMirror(mirror = new NativeMirror());
+                    }
+                    return mirror.id;
+                }
+                throw UnsupportedMessageException.raise(Message.AS_POINTER);
+            }
+        });
+    }
+
+    public static Object lookup(long address) {
+        Object result = nativeMirrors.get(address);
+        if (result == null) {
+            CompilerDirectives.transferToInterpreter();
+            throw RInternalError.shouldNotReachHere("unknown/stale native reference");
+        }
+        return result;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
index eb109fbe93..a932ec2577 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
@@ -152,8 +152,17 @@ public abstract class REnvironment extends RAttributeStorage {
         }
 
         @Override
-        public void beforeDestroy(RContext context) {
+        public void beforeDispose(RContext context) {
             beforeDestroyContext(context, this);
+            for (FrameSlot slot : globalFrame.getFrameDescriptor().getSlots()) {
+                if (globalFrame.isObject(slot)) {
+                    globalFrame.setObject(slot, null);
+                }
+            }
+            baseEnv = null;
+            namespaceRegistry = null;
+            searchPath = null;
+            parentGlobalFrame = null;
         }
 
         public static ContextStateImpl newContextState(RContext context) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
index 4bf6fc5df3..f38eb29556 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
@@ -98,7 +98,7 @@ public class DLL {
         }
 
         @Override
-        public void beforeDestroy(RContext contextArg) {
+        public void beforeDispose(RContext contextArg) {
             if (!isShareDLLKind(context.getKind())) {
                 for (int i = 1; i < list.size(); i++) {
                     DLLInfo dllInfo = list.get(i);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/AccessVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/AccessVector.java
new file mode 100644
index 0000000000..13fc7233e5
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/AccessVector.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ops;
+
+import static com.oracle.truffle.r.runtime.RRuntime.isNA;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+
+public abstract class AccessVector {
+
+    public static final class Int<T extends RAbstractIntVector, S> extends Node {
+
+        @SuppressWarnings("unchecked")
+        public S init(T vector) {
+            return (S) vector;
+        }
+
+        @SuppressWarnings("unchecked")
+        public int getInt(S store, int index) {
+            return ((T) store).getDataAt(index);
+        }
+    }
+}
diff --git a/mx.fastr/mx_fastr_dists.py b/mx.fastr/mx_fastr_dists.py
index 6ef478f23a..2915fac0b8 100644
--- a/mx.fastr/mx_fastr_dists.py
+++ b/mx.fastr/mx_fastr_dists.py
@@ -164,7 +164,7 @@ class FastRNativeRecommendedProject(mx.NativeProject):
     This finesses an ordering problem on installing the recommended R packages.
     These must be installed by FastR using bin/R CMD INSTALL. That will invoke a
     nested 'mx R' invocation which requires the FASTR distribution to be available.
-    However, this dependency cannt be specified in the suite.py file so we achieve
+    However, this dependency cannot be specified in the suite.py file so we achieve
     it here by ensuring that it is built prior to the native.recommended project.
     '''
     def __init__(self, suite, name, deps, workingSets, theLicense, **args):
-- 
GitLab