From eb7126cb346a5d9a076e774cc43f9fedc73b22e8 Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Wed, 23 Nov 2016 11:08:25 -0800
Subject: [PATCH] abstract the representation of external symbols

---
 .../truffle/r/library/graphics/RGraphics.java |   2 +-
 .../library/methods/MethodsListDispatch.java  |   3 +-
 .../fficall/src/jni/Rinternals.c              |  14 ++-
 .../fficall/src/jniboot/jniboot.c             |   8 +-
 .../nodes/builtin/base/DynLoadFunctions.java  |   6 +-
 .../builtin/base/HiddenInternalFunctions.java |   2 +-
 .../r/nodes/builtin/base/foreign/DotC.java    |  15 +--
 .../base/foreign/ForeignFunctions.java        |  15 +--
 .../r/runtime/ffi/generic/Generic_Grid.java   |  13 ++-
 .../r/runtime/ffi/generic/Generic_Tools.java  |   8 +-
 .../truffle/r/runtime/ffi/jni/JNI_C.java      |   5 +-
 .../truffle/r/runtime/ffi/jni/JNI_Call.java   |  13 ++-
 .../truffle/r/runtime/ffi/jni/JNI_DLL.java    |  74 +++++++++++++
 .../r/runtime/ffi/jni/JNI_PkgInit.java        |   3 +-
 .../r/runtime/ffi/jni/JNI_RFFIFactory.java    |  11 ++
 .../truffle/r/runtime/ffi/jni/JNI_Stats.java  |  21 ++--
 .../r/runtime/ffi/jni/JNI_UserRng.java        |   8 +-
 .../oracle/truffle/r/runtime/RDeparse.java    |   2 +-
 .../oracle/truffle/r/runtime/RSerialize.java  |   3 +-
 .../truffle/r/runtime/conn/RConnection.java   |   2 +-
 .../truffle/r/runtime/data/RDataFactory.java  |   7 +-
 .../truffle/r/runtime/data/RExternalPtr.java  |  19 ++--
 .../oracle/truffle/r/runtime/ffi/CRFFI.java   |   8 +-
 .../truffle/r/runtime/ffi/CallRFFI.java       |   8 +-
 .../com/oracle/truffle/r/runtime/ffi/DLL.java | 103 ++++++++++++------
 .../oracle/truffle/r/runtime/ffi/DLLRFFI.java |  55 ++++++++++
 .../oracle/truffle/r/runtime/ffi/RFFI.java    |   3 +
 .../truffle/r/runtime/rng/user/UserRNG.java   |  20 ++--
 28 files changed, 328 insertions(+), 123 deletions(-)
 create mode 100644 com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java
 create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java

diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java
index bc7dc453e6..c87b109962 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java
@@ -61,7 +61,7 @@ public class RGraphics {
                 registerBaseGraphicsSystem();
             } else {
                 DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
-                long func = DLL.findSymbol("InitGraphics", null, rns);
+                DLL.SymbolHandle func = DLL.findSymbol("InitGraphics", null, rns);
                 assert func != DLL.SYMBOL_NOT_FOUND;
                 RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(func, "InitGraphics", new Object[0]);
             }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
index 3155f9880e..88da7a9813 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
@@ -53,6 +53,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
@@ -418,7 +419,7 @@ public class MethodsListDispatch {
             // whose only purpose is to throw an error indicating that it shouldn't be called
             // TODO: finesse error handling in case a function stored in this pointer is actually
             // called
-            return RDataFactory.createExternalPtr(0, RNull.instance, RNull.instance);
+            return RDataFactory.createExternalPtr(new DLL.SymbolHandle(0L), RNull.instance, RNull.instance);
         }
     }
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
index 037edd13c8..16f188e378 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -114,6 +114,9 @@ static jclass handlerStacksClass;
 static jmethodID resetAndGetHandlerStacksMethodID;
 static jmethodID restoreHandlerStacksMethodID;
 
+static jclass SymbolHandleClass;
+static jmethodID symbolHandleConsMethodID;
+
 static jclass RExternalPtrClass;
 static jmethodID createExternalPtrMethodID;
 static jmethodID externalPtrGetAddrMethodID;
@@ -217,14 +220,16 @@ void init_internals(JNIEnv *env) {
 	restoreHandlerStacksMethodID = checkGetMethodID(env, rErrorHandlingClass, "restoreHandlerStacks", "(Lcom/oracle/truffle/r/runtime/RErrorHandling$HandlerStacks;)V", 1);
 
 	RExternalPtrClass = checkFindClass(env, "com/oracle/truffle/r/runtime/data/RExternalPtr");
-	createExternalPtrMethodID = checkGetMethodID(env, RDataFactoryClass, "createExternalPtr", "(JLjava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 1);
-	externalPtrGetAddrMethodID = checkGetMethodID(env, RExternalPtrClass, "getAddr", "()J", 0);
+	createExternalPtrMethodID = checkGetMethodID(env, RDataFactoryClass, "createExternalPtr", "(Lcom/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle;Ljava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 1);
+	externalPtrGetAddrMethodID = checkGetMethodID(env, RExternalPtrClass, "getAddr", "()Lcom/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle;", 0);
 	externalPtrGetTagMethodID = checkGetMethodID(env, RExternalPtrClass, "getTag", "()Ljava/lang/Object;", 0);
 	externalPtrGetProtMethodID = checkGetMethodID(env, RExternalPtrClass, "getProt", "()Ljava/lang/Object;", 0);
-	externalPtrSetAddrMethodID = checkGetMethodID(env, RExternalPtrClass, "setAddr", "(J)V", 0);
+	externalPtrSetAddrMethodID = checkGetMethodID(env, RExternalPtrClass, "setAddr", "(Lcom/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle;)V", 0);
 	externalPtrSetTagMethodID = checkGetMethodID(env, RExternalPtrClass, "setTag", "(Ljava/lang/Object;)V", 0);
 	externalPtrSetProtMethodID = checkGetMethodID(env, RExternalPtrClass, "setProt", "(Ljava/lang/Object;)V", 0);
 
+	SymbolHandleClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/DLL$SymbolHandle");
+	symbolHandleConsMethodID = checkGetMethodID(env, SymbolHandleClass, "<init>", "(Ljava/lang/Object;)V", 0);
 	CharSXPWrapperClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper$CharSXPWrapper");
 	CharSXPWrapperContentsFieldID = checkGetFieldID(env, CharSXPWrapperClass, "contents", "Ljava/lang/String;", 0);
 
@@ -1503,7 +1508,8 @@ SEXP R_forceAndCall(SEXP e, int n, SEXP rho) {
 
 SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, createExternalPtrMethodID, (jlong) p, tag, prot);
+	jobject handle = (*thisenv)->CallStaticObjectMethod(thisenv, SymbolHandleClass, symbolHandleConsMethodID, (jobject) p);
+	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, RDataFactoryClass, createExternalPtrMethodID, handle, tag, prot);
     return checkRef(thisenv, result);
 }
 
diff --git a/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c b/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c
index aa51df6764..22aab408ee 100644
--- a/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c
+++ b/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c
@@ -48,7 +48,7 @@ static void create_dlerror_string(JNIEnv *env) {
 }
 
 JNIEXPORT jlong JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Base_native_1dlopen(JNIEnv *env, jclass c, jstring jpath, jboolean local, jboolean now) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlopen(JNIEnv *env, jclass c, jstring jpath, jboolean local, jboolean now) {
     const char *path = (*env)->GetStringUTFChars(env, jpath, NULL);
     int flags = (local ? RTLD_LOCAL : RTLD_GLOBAL) | (now ? RTLD_NOW : RTLD_LAZY);
     void *handle = dlopen(path, flags);
@@ -60,7 +60,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Base_native_1dlopen(JNIEnv *env,
 }
 
 JNIEXPORT jlong JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Base_native_1dlsym(JNIEnv *env, jclass c, jlong handle, jstring jsymbol) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlsym(JNIEnv *env, jclass c, jlong handle, jstring jsymbol) {
     const char *symbol = (*env)->GetStringUTFChars(env, jsymbol, NULL);
     void *address = dlsym((void *)handle, symbol);
     create_dlerror_string(env);
@@ -69,13 +69,13 @@ Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Base_native_1dlsym(JNIEnv *env, j
 }
 
 JNIEXPORT jint JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Base_native_1dlclose(JNIEnv *env, jclass c, jlong handle) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlclose(JNIEnv *env, jclass c, jlong handle) {
     int rc = dlclose((void *)handle);
     return rc;
 }
 
 JNIEXPORT jobject JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Base_native_1dlerror(JNIEnv *env, jclass c) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlerror(JNIEnv *env, jclass c) {
    	return last_dlerror;
 }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
index 09557dc390..6ef837a033 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
@@ -164,7 +164,7 @@ public class DynLoadFunctions {
         @TruffleBoundary
         protected Object getSymbolInfo(String symbol, String packageName, boolean withReg) {
             DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
-            long f = DLL.findSymbol(RRuntime.asString(symbol), packageName, rns);
+            DLL.SymbolHandle f = DLL.findSymbol(RRuntime.asString(symbol), packageName, rns);
             SymbolInfo symbolInfo = null;
             if (f != DLL.SYMBOL_NOT_FOUND) {
                 symbolInfo = new SymbolInfo(rns.getDllInfo(), symbol, f);
@@ -175,14 +175,14 @@ public class DynLoadFunctions {
         @Specialization(guards = "isDLLInfo(externalPtr)")
         @TruffleBoundary
         protected Object getSymbolInfo(RAbstractStringVector symbolVec, RExternalPtr externalPtr, boolean withReg) {
-            DLL.DLLInfo dllInfo = DLL.getDLLInfoForId((int) externalPtr.getAddr());
+            DLL.DLLInfo dllInfo = DLL.getDLLInfoForId((int) externalPtr.getAddr().asAddress());
             if (dllInfo == null) {
                 throw RError.error(this, RError.Message.REQUIRES_NAME_DLLINFO);
             }
 
             DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
             String symbol = symbolVec.getDataAt(0);
-            long f = DLL.dlsym(dllInfo, RRuntime.asString(symbol), rns);
+            DLL.SymbolHandle f = DLL.dlsym(dllInfo, RRuntime.asString(symbol), rns);
             SymbolInfo symbolInfo = null;
             if (f != DLL.SYMBOL_NOT_FOUND) {
                 symbolInfo = new SymbolInfo(dllInfo, symbol, f);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
index 9c2419064f..ff6b649c54 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
@@ -285,7 +285,7 @@ public class HiddenInternalFunctions {
         @TruffleBoundary
         protected RList getRegisteredRoutines(RExternalPtr externalPtr) {
             Object[] data = new Object[NAMES.getLength()];
-            DLL.DLLInfo dllInfo = DLL.getDLLInfoForId((int) externalPtr.getAddr());
+            DLL.DLLInfo dllInfo = DLL.getDLLInfoForId((int) externalPtr.getAddr().asAddress());
             RInternalError.guarantee(dllInfo != null);
             for (DLL.NativeSymbolType nst : DLL.NativeSymbolType.values()) {
                 DLL.DotSymbol[] symbols = dllInfo.getNativeSymbols(nst);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java
index 60f28c4e3c..265141a16e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java
@@ -42,6 +42,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
@@ -75,9 +76,9 @@ public abstract class DotC extends RBuiltinNode {
     @SuppressWarnings("unused")
     @Specialization
     protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding) {
-        long address = getAddressFromSymbolInfo(frame, symbol);
+        SymbolHandle handle = getAddressFromSymbolInfo(frame, symbol);
         String name = getNameFromSymbolInfo(frame, symbol);
-        return dispatch(this, address, name, naok, dup, args);
+        return dispatch(this, handle, name, naok, dup, args);
     }
 
     @SuppressWarnings("unused")
@@ -93,8 +94,8 @@ public abstract class DotC extends RBuiltinNode {
             }
         }
         DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.C, null, null);
-        long func = DLL.findSymbol(f.getDataAt(0), libName, rns);
-        if (func == -1) {
+        DLL.SymbolHandle func = DLL.findSymbol(f.getDataAt(0), libName, rns);
+        if (func == DLL.SYMBOL_NOT_FOUND) {
             errorProfile.enter();
             throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, f);
         }
@@ -109,7 +110,7 @@ public abstract class DotC extends RBuiltinNode {
         return RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
     }
 
-    private long getAddressFromSymbolInfo(VirtualFrame frame, RList symbol) {
+    private SymbolHandle getAddressFromSymbolInfo(VirtualFrame frame, RList symbol) {
         if (addressExtract == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
@@ -150,7 +151,7 @@ public abstract class DotC extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    protected static RList dispatch(RBuiltinNode node, long address, String name, byte naok, byte dup, RArgsValuesAndNames args) {
+    protected static RList dispatch(RBuiltinNode node, SymbolHandle handle, String name, byte naok, byte dup, RArgsValuesAndNames args) {
         @SuppressWarnings("unused")
         boolean dupArgs = RRuntime.fromLogical(dup);
         @SuppressWarnings("unused")
@@ -193,7 +194,7 @@ public abstract class DotC extends RBuiltinNode {
         if (FastROptions.TraceNativeCalls.getBooleanValue()) {
             trace(name, nativeArgs);
         }
-        RFFIFactory.getRFFI().getCRFFI().invoke(address, nativeArgs);
+        RFFIFactory.getRFFI().getCRFFI().invoke(handle, nativeArgs);
         // we have to assume that the native method updated everything
         RStringVector listNames = validateArgNames(array.length, args.getSignature());
         Object[] results = new Object[array.length];
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
index f059e6c94b..00c87f59e8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
@@ -96,6 +96,7 @@ import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
@@ -194,7 +195,7 @@ public class ForeignFunctions {
             return RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
         }
 
-        protected long getAddressFromSymbolInfo(VirtualFrame frame, RList symbol) {
+        protected SymbolHandle getAddressFromSymbolInfo(VirtualFrame frame, RList symbol) {
             if (addressExtract == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
@@ -263,7 +264,7 @@ public class ForeignFunctions {
                         @Cached("create()") BranchProfile errorProfile) {
             String libName = checkPackageArg(rPackage, errorProfile);
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Fortran, null, null);
-            long func = DLL.findSymbol(f.getDataAt(0), libName, rns);
+            DLL.SymbolHandle func = DLL.findSymbol(f.getDataAt(0), libName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, f);
@@ -553,7 +554,7 @@ public class ForeignFunctions {
         @Specialization
         protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Call, null, null);
-            long func = DLL.findSymbol(name, packageName, rns);
+            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
@@ -640,7 +641,7 @@ public class ForeignFunctions {
         @Specialization
         protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.External, null, null);
-            long func = DLL.findSymbol(name, packageName, rns);
+            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
@@ -713,7 +714,7 @@ public class ForeignFunctions {
         @Specialization
         protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.External, null, null);
-            long func = DLL.findSymbol(name, packageName, rns);
+            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
@@ -771,7 +772,7 @@ public class ForeignFunctions {
         @Specialization
         protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.External, null, null);
-            long func = DLL.findSymbol(name, packageName, rns);
+            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
@@ -827,7 +828,7 @@ public class ForeignFunctions {
         @TruffleBoundary
         protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Call, null, null);
-            long func = DLL.findSymbol(name, packageName, rns);
+            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java
index a5fdc39ac4..5abe50b8ca 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java
@@ -28,12 +28,13 @@ import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.GridRFFI;
 import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
 public class Generic_Grid implements GridRFFI {
     private static final class GridProvider {
         private static GridProvider grid;
-        private static long initGrid;
-        private static long killGrid;
+        private static DLL.SymbolHandle initGrid;
+        private static DLL.SymbolHandle killGrid;
 
         @TruffleBoundary
         private GridProvider() {
@@ -52,24 +53,24 @@ public class Generic_Grid implements GridRFFI {
 
         @SuppressWarnings("static-method")
         long getInitGrid() {
-            return initGrid;
+            return initGrid.asAddress();
         }
 
         @SuppressWarnings("static-method")
         long getKillGrid() {
-            return killGrid;
+            return killGrid.asAddress();
         }
     }
 
     @Override
     public Object initGrid(REnvironment gridEvalEnv) {
         long initGrid = GridProvider.gridProvider().getInitGrid();
-        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(initGrid, "L_initGrid", new Object[]{gridEvalEnv});
+        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new SymbolHandle(initGrid), "L_initGrid", new Object[]{gridEvalEnv});
     }
 
     @Override
     public Object killGrid() {
         long killGrid = GridProvider.gridProvider().getKillGrid();
-        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(killGrid, "L_killGrid", new Object[0]);
+        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new SymbolHandle(killGrid), "L_killGrid", new Object[0]);
     }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java
index d8504e0c04..a97616f45f 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java
@@ -31,6 +31,7 @@ import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
@@ -39,7 +40,7 @@ public class Generic_Tools implements ToolsRFFI {
     private static final class ToolsProvider {
         private static final String C_PARSE_RD = "C_parseRd";
         private static ToolsProvider tools;
-        private static long parseRd;
+        private static DLL.SymbolHandle parseRd;
 
         @TruffleBoundary
         private ToolsProvider() {
@@ -57,7 +58,7 @@ public class Generic_Tools implements ToolsRFFI {
 
         @SuppressWarnings("static-method")
         long getParseRd() {
-            return parseRd;
+            return parseRd.asAddress();
         }
     }
 
@@ -70,7 +71,8 @@ public class Generic_Tools implements ToolsRFFI {
         try {
             parseRdCritical.acquire();
             long parseRd = ToolsProvider.toolsProvider().getParseRd();
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(parseRd, ToolsProvider.C_PARSE_RD, new Object[]{con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups});
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new SymbolHandle(parseRd), ToolsProvider.C_PARSE_RD,
+                            new Object[]{con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups});
         } catch (Throwable ex) {
             throw RInternalError.shouldNotReachHere(ex, "error during Rd parsing");
         } finally {
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
index 160d050b37..174ad3844f 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.ffi.jni;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
 public class JNI_C implements CRFFI {
 
@@ -35,8 +36,8 @@ public class JNI_C implements CRFFI {
      */
     @Override
     @TruffleBoundary
-    public synchronized void invoke(long address, Object[] args) {
-        c(address, args);
+    public synchronized void invoke(SymbolHandle symbolHandle, Object[] args) {
+        c(symbolHandle.asAddress(), args);
     }
 
     private static native void c(long address, Object[] args);
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
index 3d3fb55004..16aabaea92 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
@@ -28,10 +28,11 @@ import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceEnabled;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLException;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
@@ -46,7 +47,7 @@ import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
  */
 public class JNI_Call implements CallRFFI {
 
-    JNI_Call() {
+    protected JNI_Call() {
         loadLibrary();
     }
 
@@ -60,7 +61,7 @@ public class JNI_Call implements CallRFFI {
      * so we have to do an additional {@code System.load} to achieve that.
      *
      * Before we do that we must load {@code libjniboot} because the implementation of
-     * {@link BaseRFFI#dlopen} is called by {@link DLL#load} which uses JNI!
+     * {@link DLLRFFI#dlopen} is called by {@link DLL#load} which uses JNI!
      */
     @TruffleBoundary
     private static void loadLibrary() {
@@ -90,7 +91,8 @@ public class JNI_Call implements CallRFFI {
 
     @Override
     @TruffleBoundary
-    public synchronized Object invokeCall(long address, String name, Object[] args) {
+    public synchronized Object invokeCall(SymbolHandle handleArg, String name, Object[] args) {
+        long address = handleArg.asAddress();
         Object result = null;
         if (traceEnabled()) {
             traceDownCall(name, args);
@@ -150,10 +152,11 @@ public class JNI_Call implements CallRFFI {
 
     @Override
     @TruffleBoundary
-    public synchronized void invokeVoidCall(long address, String name, Object[] args) {
+    public synchronized void invokeVoidCall(SymbolHandle handle, String name, Object[] args) {
         if (traceEnabled()) {
             traceDownCall(name, args);
         }
+        long address = handle.asAddress();
         try {
             switch (args.length) {
                 case 0:
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java
new file mode 100644
index 0000000000..236b81e004
--- /dev/null
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi.jni;
+
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
+
+public class JNI_DLL implements DLLRFFI {
+
+    @Override
+    public Object dlopen(String path, boolean local, boolean now) {
+        long handle = native_dlopen(path, local, now);
+        if (handle == 0) {
+            return null;
+        } else {
+            return new Long(handle);
+        }
+    }
+
+    @Override
+    public SymbolHandle dlsym(Object handle, String symbol) {
+        long nativeHandle = (Long) handle;
+        long symv = native_dlsym(nativeHandle, symbol);
+        if (symv == 0) {
+            // symbol might actually be zero
+            if (dlerror() != null) {
+                return null;
+            }
+        }
+        return new SymbolHandle(symv);
+    }
+
+    @Override
+    public int dlclose(Object handle) {
+        long nativeHandle = (Long) handle;
+        return native_dlclose(nativeHandle);
+    }
+
+    @Override
+    public String dlerror() {
+        return native_dlerror();
+    }
+
+    // Checkstyle: stop method name check
+
+    private static native long native_dlopen(String path, boolean local, boolean now);
+
+    private static native int native_dlclose(long handle);
+
+    private static native String native_dlerror();
+
+    private static native long native_dlsym(long handle, String symbol);
+
+}
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PkgInit.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PkgInit.java
index a93b6008d6..d5c2450edf 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PkgInit.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PkgInit.java
@@ -26,6 +26,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
 /**
  * The JNI-based implementation of the package init code. This is only up-called from JNI.
@@ -55,7 +56,7 @@ final class JNI_PkgInit {
      * Upcall from native to create a {@link DotSymbol} value.
      */
     private static DotSymbol setDotSymbolValues(String name, long fun, int numArgs) {
-        return new DotSymbol(name, fun, numArgs);
+        return new DotSymbol(name, new SymbolHandle(fun), numArgs);
     }
 
     private static native DotSymbol setSymbol(int nstOrd, long routines, int index);
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java
index af726e7ecd..546352c06e 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java
@@ -29,6 +29,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
+import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.GridRFFI;
 import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
@@ -195,6 +196,16 @@ public class JNI_RFFIFactory extends RFFIFactory implements RFFI {
         return pcreRFFI;
     }
 
+    private DLLRFFI dllRFFI;
+
+    @Override
+    public DLLRFFI getDLLRFFI() {
+        if (dllRFFI == null) {
+            dllRFFI = new JNI_DLL();
+        }
+        return dllRFFI;
+    }
+
     private REmbedRFFI rEmbedRFFI;
 
     @Override
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java
index 460515618e..1f0564d90b 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java
@@ -26,6 +26,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
 
 // Checkstyle: stop method name
@@ -33,31 +34,31 @@ public class JNI_Stats implements StatsRFFI {
     @Override
     @TruffleBoundary
     public void fft_factor(int n, int[] pmaxf, int[] pmaxp) {
-        native_fft_factor(fft_factor_address(), n, pmaxf, pmaxp);
+        native_fft_factor(fft_factor_address().asAddress(), n, pmaxf, pmaxp);
     }
 
     @Override
     @TruffleBoundary
     public int fft_work(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
-        return native_fft_work(fft_work_address(), a, nseg, n, nspn, isn, work, iwork);
+        return native_fft_work(fft_work_address().asAddress(), a, nseg, n, nspn, isn, work, iwork);
     }
 
-    private long fft_factor_address;
-    private long fft_work_address;
+    private SymbolHandle fft_factor_address;
+    private SymbolHandle fft_work_address;
 
-    private long fft_factor_address() {
-        if (fft_factor_address == 0) {
+    private SymbolHandle fft_factor_address() {
+        if (fft_factor_address == null) {
             DLLInfo dllInfo = DLL.findLibrary("stats");
-            fft_factor_address = RFFIFactory.getRFFI().getBaseRFFI().dlsym(dllInfo.handle, "fft_factor");
+            fft_factor_address = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, "fft_factor");
             assert fft_factor_address != DLL.SYMBOL_NOT_FOUND;
         }
         return fft_factor_address;
     }
 
-    private long fft_work_address() {
-        if (fft_work_address == 0) {
+    private SymbolHandle fft_work_address() {
+        if (fft_work_address == null) {
             DLLInfo dllInfo = DLL.findLibrary("stats");
-            fft_work_address = RFFIFactory.getRFFI().getBaseRFFI().dlsym(dllInfo.handle, "fft_work");
+            fft_work_address = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, "fft_work");
             assert fft_work_address != DLL.SYMBOL_NOT_FOUND;
         }
         return fft_work_address;
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java
index bc935d7b32..1387cb869a 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java
@@ -30,26 +30,26 @@ public class JNI_UserRng implements UserRngRFFI {
     @Override
     @TruffleBoundary
     public void init(int seed) {
-        init(Function.Init.getAddress(), seed);
+        init(Function.Init.getSymbolHandle().asAddress(), seed);
 
     }
 
     @Override
     @TruffleBoundary
     public double rand() {
-        return rand(Function.Rand.getAddress());
+        return rand(Function.Rand.getSymbolHandle().asAddress());
     }
 
     @Override
     @TruffleBoundary
     public int nSeed() {
-        return nSeed(Function.NSeed.getAddress());
+        return nSeed(Function.NSeed.getSymbolHandle().asAddress());
     }
 
     @Override
     @TruffleBoundary
     public void seeds(int[] n) {
-        seeds(Function.Seedloc.getAddress(), n);
+        seeds(Function.Seedloc.getSymbolHandle().asAddress(), n);
     }
 
     private static native void init(long address, int seed);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
index 0eb828df88..d7339d4988 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
@@ -681,7 +681,7 @@ public class RDeparse {
                 }
                 append(')');
             } else if (value instanceof RExternalPtr) {
-                append("<pointer: 0x").append(Long.toHexString(((RExternalPtr) value).getAddr())).append('>');
+                append("<pointer: 0x").append(Long.toHexString(((RExternalPtr) value).getAddr().asAddress())).append('>');
             } else if (value instanceof REnvironment) {
                 append("<environment>");
             } else if (value instanceof TruffleObject) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index 5d7fa9e540..544a6136ab 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -76,6 +76,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
+import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
@@ -787,7 +788,7 @@ public class RSerialize {
                     Object prot = readItem();
                     long addr = 0;
                     Object tag = readItem();
-                    result = RDataFactory.createExternalPtr(addr, tag, prot);
+                    result = RDataFactory.createExternalPtr(new DLL.SymbolHandle(addr), tag, prot);
                     addReadRef(result);
                     break;
                 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
index 8717d9a2d7..8bb9e8e877 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
@@ -54,7 +54,7 @@ public abstract class RConnection implements AutoCloseable {
 
         RStringVector classVector = RDataFactory.createStringVector(classes, RDataFactory.COMPLETE_VECTOR);
         // it's important to put "this" into the externalptr, so that it doesn't get collected
-        RExternalPtr connectionId = RDataFactory.createExternalPtr(0, this, RDataFactory.createSymbol("connection"), RNull.instance);
+        RExternalPtr connectionId = RDataFactory.createExternalPtr(null, this, RDataFactory.createSymbol("connection"), RNull.instance);
         result.initAttributes(RAttributes.createInitialized(new String[]{RRuntime.CLASS_ATTR_KEY, "conn_id"}, new Object[]{classVector, connectionId}));
 
         return result;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index 3ecd606d1a..a510e07cfe 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -43,6 +43,7 @@ import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RPromise.EagerFeedback;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseState;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
@@ -495,19 +496,19 @@ public final class RDataFactory {
         return traceDataCreated(new RS4Object());
     }
 
-    public static RExternalPtr createExternalPtr(long value, Object externalObject, Object tag, Object prot) {
+    public static RExternalPtr createExternalPtr(SymbolHandle value, Object externalObject, Object tag, Object prot) {
         assert tag != null : "null tag, use RNull.instance instead";
         assert prot != null : "null prot, use RNull.instance instead";
         return traceDataCreated(new RExternalPtr(value, externalObject, tag, prot));
     }
 
-    public static RExternalPtr createExternalPtr(long value, Object tag, Object prot) {
+    public static RExternalPtr createExternalPtr(SymbolHandle value, Object tag, Object prot) {
         assert tag != null : "null tag, use RNull.instance instead";
         assert prot != null : "null prot, use RNull.instance instead";
         return traceDataCreated(new RExternalPtr(value, null, tag, prot));
     }
 
-    public static RExternalPtr createExternalPtr(long value, Object tag) {
+    public static RExternalPtr createExternalPtr(SymbolHandle value, Object tag) {
         assert tag != null : "null tag, use RNull.instance instead";
         return traceDataCreated(new RExternalPtr(value, null, tag, RNull.instance));
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java
index 1d4124eaab..2932ecbe2b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java
@@ -23,29 +23,30 @@
 package com.oracle.truffle.r.runtime.data;
 
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
 /**
  * The rarely seen {@code externalptr} type.
  */
-public class RExternalPtr extends RAttributeStorage {
-    private long addr;
+public class RExternalPtr extends RAttributeStorage implements RTypedValue {
+    private SymbolHandle handle;
     private Object tag;
     private Object prot;
     private Object externalObject;
 
-    RExternalPtr(long addr, Object externalObject, Object tag, Object prot) {
-        this.addr = addr;
+    RExternalPtr(SymbolHandle handle, Object externalObject, Object tag, Object prot) {
+        this.handle = handle;
         this.externalObject = externalObject;
         this.tag = tag;
         this.prot = prot;
     }
 
     public RExternalPtr copy() {
-        return RDataFactory.createExternalPtr(addr, externalObject, tag, prot);
+        return RDataFactory.createExternalPtr(handle, externalObject, tag, prot);
     }
 
-    public long getAddr() {
-        return addr;
+    public SymbolHandle getAddr() {
+        return handle;
     }
 
     public Object getExternalObject() {
@@ -60,8 +61,8 @@ public class RExternalPtr extends RAttributeStorage {
         return prot;
     }
 
-    public void setAddr(long value) {
-        this.addr = value;
+    public void setAddr(SymbolHandle value) {
+        this.handle = value;
     }
 
     public void setExternalObject(Object externalObject) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
index 2ccb32e90b..a1b7d4fc55 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+
 /**
  * Support for the {.C} and {.Fortran} calls.
  */
@@ -31,8 +33,8 @@ public interface CRFFI {
      * {@code args}. The values in {@code args} should be native types,e.g., {@code double[]} not
      * {@code RDoubleVector}.
      *
-     * @param address the target address of the native method
+     * @param handle of the native method
      * @param args native arguments
      */
-    void invoke(long address, Object[] args);
+    void invoke(SymbolHandle handle, Object[] args);
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
index 76c8f10cd0..6baeebaae6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+
 /**
  * Support for the {.Call} and {.External} calls.
  */
@@ -31,16 +33,16 @@ public interface CallRFFI {
      * {@code args}. The values in {@code args} can be any of the types used to represent {@code R}
      * values in the implementation.
      *
-     * @param address the address of the native function
+     * @param handle the address of the native function
      * @param name the name of the native function
      * @param args arguments
      */
-    Object invokeCall(long address, String name, Object[] args);
+    Object invokeCall(SymbolHandle handle, String name, Object[] args);
 
     /**
      * Variant that does not return a result (primarily for library "init" methods).
      */
-    void invokeVoidCall(long address, String name, Object[] args);
+    void invokeVoidCall(SymbolHandle handle, String name, Object[] args);
 
     /**
      * This interface is instantiated very early and sets the FFI global variables as part of that
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 28b50af8c8..5b3af3bb9d 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
@@ -19,8 +19,10 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.RErrorException;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.Utils;
@@ -30,6 +32,7 @@ import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.RTruffleObject;
 
 /**
  * Support for Dynamically Loaded Libraries.
@@ -52,8 +55,6 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
  */
 public class DLL {
 
-    public static final long SYMBOL_NOT_FOUND = -1;
-
     /**
      * The list of loaded DLLs.
      */
@@ -64,6 +65,14 @@ public class DLL {
      */
     private static final AtomicInteger ID = new AtomicInteger();
 
+    public static Deque<DLLInfo> getList() {
+        return list;
+    }
+
+    public static void addDLL(DLLInfo dllInfo) {
+        list.add(dllInfo);
+    }
+
     public enum NativeSymbolType {
         C,
         Call,
@@ -77,16 +86,17 @@ public class DLL {
      * Denotes info in registered native routines. GnuR has "subclasses" for C/Fortran, which is TBD
      * for FastR.
      */
-    public static class DotSymbol {
+    public static class DotSymbol implements RTruffleObject {
         public final String name;
-        public final long fun;
+        public final SymbolHandle fun;
         public final int numArgs;
 
-        public DotSymbol(String name, long fun, int numArgs) {
+        public DotSymbol(String name, SymbolHandle fun, int numArgs) {
             this.name = name;
             this.fun = fun;
             this.numArgs = numArgs;
         }
+
     }
 
     public static class RegisteredNativeSymbol {
@@ -110,7 +120,7 @@ public class DLL {
 
     }
 
-    public static final class DLLInfo {
+    public static final class DLLInfo implements RTruffleObject {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"name", "path", "dynamicLookup", "handle", "info"}, RDataFactory.COMPLETE_VECTOR);
         public static final String DLL_INFO_REFERENCE = "DLLInfoReference";
         private static final RStringVector INFO_REFERENCE_CLASS = RDataFactory.createStringVectorFromScalar(DLL_INFO_REFERENCE);
@@ -178,13 +188,13 @@ public class DLL {
             data[0] = name;
             data[1] = path;
             data[2] = RRuntime.asLogical(dynamicLookup);
-            data[3] = createExternalPtr(System.identityHashCode(handle), HANDLE_CLASS);
+            data[3] = createExternalPtr(new SymbolHandle(new Long(System.identityHashCode(handle))), HANDLE_CLASS);
             /*
              * GnuR sets the info member to an externalptr whose value is the DllInfo structure
              * itself. We can't do that, but we need a way to get back to it from R code that uses
              * the value, e.g. getRegisteredRoutines. So we use the id value.
              */
-            data[4] = createExternalPtr(id, INFO_REFERENCE_CLASS);
+            data[4] = createExternalPtr(new SymbolHandle(new Long(id)), INFO_REFERENCE_CLASS);
             RList dllInfo = RDataFactory.createList(data, DLLInfo.NAMES);
             dllInfo.setClassAttr(RDataFactory.createStringVectorFromScalar(DLLINFO_CLASS));
             return dllInfo;
@@ -194,14 +204,15 @@ public class DLL {
         public String toString() {
             return String.format("name: %s, path: %s, dynamicLookup: %b, forceSymbols %b", name, path, dynamicLookup, forceSymbols);
         }
+
     }
 
     public static class SymbolInfo {
         public final DLLInfo libInfo;
         public final String symbol;
-        public final long address;
+        public final SymbolHandle address;
 
-        public SymbolInfo(DLLInfo libInfo, String symbol, long address) {
+        public SymbolInfo(DLLInfo libInfo, String symbol, SymbolHandle address) {
             this.libInfo = libInfo;
             this.symbol = symbol;
             this.address = address;
@@ -245,6 +256,37 @@ public class DLL {
         }
     }
 
+    /**
+     * Abstracts the way that DLL function symbols are represented, either as a machine address (
+     * {@link Long}) or a {@link TruffleObject}.
+     */
+    public static class SymbolHandle {
+        public final Object value;
+
+        public SymbolHandle(Object value) {
+            assert value instanceof Long || value instanceof TruffleObject;
+            this.value = value;
+        }
+
+        public long asAddress() {
+            if (value instanceof Long) {
+                return (Long) value;
+            } else {
+                throw RInternalError.shouldNotReachHere();
+            }
+        }
+
+        public TruffleObject asTruffleObject() {
+            if (value instanceof TruffleObject) {
+                return (TruffleObject) value;
+            } else {
+                throw RInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static final SymbolHandle SYMBOL_NOT_FOUND = null;
+
     public static synchronized DLLInfo getDLLInfoForId(int id) {
         for (DLLInfo dllInfo : list) {
             if (dllInfo.id == id) {
@@ -259,7 +301,7 @@ public class DLL {
         return tag.getName().equals(DLLInfo.DLL_INFO_REFERENCE);
     }
 
-    public static RExternalPtr createExternalPtr(long value, RStringVector rClass) {
+    public static RExternalPtr createExternalPtr(SymbolHandle value, RStringVector rClass) {
         CompilerAsserts.neverPartOfCompilation(); // for interning
         RExternalPtr result = RDataFactory.createExternalPtr(value, RDataFactory.createSymbolInterned(rClass.getDataAt(0)));
         result.setClassAttr(rClass);
@@ -269,7 +311,7 @@ public class DLL {
     public static class DLLException extends RErrorException {
         private static final long serialVersionUID = 1L;
 
-        DLLException(RError.Message msg, Object... args) {
+        public DLLException(RError.Message msg, Object... args) {
             super(msg, args);
         }
     }
@@ -292,9 +334,9 @@ public class DLL {
             }
         }
         File file = new File(absPath);
-        Object handle = RFFIFactory.getRFFI().getBaseRFFI().dlopen(absPath, local, now);
+        Object handle = RFFIFactory.getRFFI().getDLLRFFI().dlopen(path, local, now);
         if (handle == null) {
-            String dlError = RFFIFactory.getRFFI().getBaseRFFI().dlerror();
+            String dlError = RFFIFactory.getRFFI().getDLLRFFI().dlerror();
             if (RContext.isInitialContextInitialized()) {
                 throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, dlError);
             } else {
@@ -316,8 +358,8 @@ public class DLL {
         DLLInfo dllInfo = load(path, local, now);
         // Search for init method
         String pkgInit = R_INIT_PREFIX + dllInfo.name;
-        long initFunc = RFFIFactory.getRFFI().getBaseRFFI().dlsym(dllInfo.handle, pkgInit);
-        if (initFunc != 0) {
+        SymbolHandle initFunc = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, pkgInit);
+        if (initFunc != SYMBOL_NOT_FOUND) {
             synchronized (DLL.class) {
                 try {
                     RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(initFunc, pkgInit, new Object[]{dllInfo});
@@ -342,7 +384,7 @@ public class DLL {
         String absPath = Utils.tildeExpand(path);
         for (DLLInfo info : list) {
             if (info.path.equals(absPath)) {
-                int rc = RFFIFactory.getRFFI().getBaseRFFI().dlclose(info.handle);
+                int rc = RFFIFactory.getRFFI().getDLLRFFI().dlclose(info.handle);
                 if (rc != 0) {
                     throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, "");
                 }
@@ -369,7 +411,7 @@ public class DLL {
      * @param rns if not {@code null} may limit the search to a specific {@link NativeSymbolType}
      * @return the address of the (function) symbol or {@code 0} if not found.
      */
-    public static long getDLLRegisteredSymbol(DLLInfo dllInfo, String name, RegisteredNativeSymbol rns) {
+    public static SymbolHandle getDLLRegisteredSymbol(DLLInfo dllInfo, String name, RegisteredNativeSymbol rns) {
         NativeSymbolType rnsNst = rns == null ? NativeSymbolType.Any : rns.nst;
         for (NativeSymbolType nst : NativeSymbolType.values()) {
             if (rnsNst == NativeSymbolType.Any || rnsNst == nst) {
@@ -398,9 +440,9 @@ public class DLL {
      * disabled, looks up the symbol using the {@code dlopen} machinery.
      */
     @TruffleBoundary
-    public static long dlsym(DLLInfo dllInfo, String name, RegisteredNativeSymbol rns) {
-        long f = getDLLRegisteredSymbol(dllInfo, name, rns);
-        if (f != -1) {
+    public static SymbolHandle dlsym(DLLInfo dllInfo, String name, RegisteredNativeSymbol rns) {
+        SymbolHandle f = getDLLRegisteredSymbol(dllInfo, name, rns);
+        if (f != SYMBOL_NOT_FOUND) {
             return f;
         }
 
@@ -413,16 +455,11 @@ public class DLL {
         if (rns != null && rns.nst == NativeSymbolType.Fortran) {
             mName = name + "_";
         }
-        f = RFFIFactory.getRFFI().getBaseRFFI().dlsym(dllInfo.handle, mName);
-        if (f != 0) {
-            return f;
+        SymbolHandle symValue = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, mName);
+        if (symValue != null) {
+            return symValue;
         } else {
-            // symbol might actually be zero
-            if (RFFIFactory.getRFFI().getBaseRFFI().dlerror() == null) {
-                return f;
-            } else {
-                return SYMBOL_NOT_FOUND;
-            }
+            return SYMBOL_NOT_FOUND;
         }
     }
 
@@ -435,14 +472,14 @@ public class DLL {
      *            {@code null})
      */
     @TruffleBoundary
-    public static synchronized long findSymbol(String name, String libName, RegisteredNativeSymbol rns) {
+    public static synchronized SymbolHandle findSymbol(String name, String libName, RegisteredNativeSymbol rns) {
         boolean all = libName == null || libName.length() == 0;
         for (DLLInfo dllInfo : list) {
             if (dllInfo.forceSymbols) {
                 continue;
             }
             if (all || dllInfo.name.equals(libName)) {
-                long func = dlsym(dllInfo, name, rns);
+                SymbolHandle func = dlsym(dllInfo, name, rns);
                 if (func != SYMBOL_NOT_FOUND) {
                     if (rns != null) {
                         rns.dllInfo = dllInfo;
@@ -469,7 +506,7 @@ public class DLL {
     @TruffleBoundary
     public static DLLInfo findLibraryContainingSymbol(String symbol) {
         RegisteredNativeSymbol rns = RegisteredNativeSymbol.any();
-        long func = findSymbol(symbol, null, rns);
+        SymbolHandle func = findSymbol(symbol, null, rns);
         if (func == SYMBOL_NOT_FOUND) {
             return null;
         } else {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java
new file mode 100644
index 0000000000..3659d2f7e2
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+
+public interface DLLRFFI {
+    /**
+     * Open a DLL.
+     *
+     * @return {@code null} on error, opaque handle for following calls otherwise.
+     */
+    Object dlopen(String path, boolean local, boolean now);
+
+    /**
+     * Search for {@code symbol} in DLL specified by {@code handle}. To accommodate differing
+     * implementations of this interface the result is {@link SymbolHandle}. For the standard OS
+     * implementation this will encapsulate a {@link Long} or {@code null} if an error occurred.
+     *
+     */
+    SymbolHandle dlsym(Object handle, String symbol);
+
+    /**
+     * Close DLL specified by {@code handle}.
+     */
+    int dlclose(Object handle);
+
+    /**
+     * Get any error message.
+     *
+     * @return {@code null} if no error, message otherwise.
+     */
+    String dlerror();
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
index a88e98267e..99378fa1af 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
@@ -39,6 +39,7 @@ package com.oracle.truffle.r.runtime.ffi;
  * <li>{@link UserRngRFFI}: specific interface to user-supplied random number generator.</li>
  * <li>{@link PCRERFFI}: interface to PCRE library (Perl regexp).</li>
  * <li>{@link ZipRFFI}: interface to zip compression</li>
+ * <li>{@link DLLRFFI}: interface to dll functions, e.g., {@code dlopen}</li>
  * <li>{@link REmbedRFFI}: interface to embedded support</li>
  * <li>{@link MiscRFFI}: interface to miscellaneous native functions</li>
  * </ul>
@@ -69,6 +70,8 @@ public interface RFFI {
 
     ZipRFFI getZipRFFI();
 
+    DLLRFFI getDLLRFFI();
+
     REmbedRFFI getREmbedRFFI();
 
     MiscRFFI getMiscRFFI();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java
index 9e1f745d76..994950b30f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java
@@ -43,7 +43,7 @@ public final class UserRNG extends RNGInitAdapter {
         NSeed(OPTIONAL),
         Seedloc(OPTIONAL);
 
-        private long address;
+        private DLL.SymbolHandle symbolHandle;
         private final String symbol;
         private final boolean optional;
 
@@ -53,15 +53,15 @@ public final class UserRNG extends RNGInitAdapter {
         }
 
         private boolean isDefined() {
-            return address != 0;
+            return symbolHandle != null;
         }
 
-        public long getAddress() {
-            return address;
+        public DLL.SymbolHandle getSymbolHandle() {
+            return symbolHandle;
         }
 
-        private void setAddress(DLLInfo dllInfo) {
-            this.address = findSymbol(symbol, dllInfo, optional);
+        private void setSymbolHandle(DLLInfo dllInfo) {
+            this.symbolHandle = findSymbol(symbol, dllInfo, optional);
         }
 
     }
@@ -77,7 +77,7 @@ public final class UserRNG extends RNGInitAdapter {
             throw RError.error(RError.NO_CALLER, RError.Message.RNG_SYMBOL, Function.Rand.symbol);
         }
         for (Function f : Function.values()) {
-            f.setAddress(dllInfo);
+            f.setSymbolHandle(dllInfo);
         }
         userRngRFFI = RFFIFactory.getRFFI().getUserRngRFFI();
         if (Function.Init.isDefined()) {
@@ -100,13 +100,13 @@ public final class UserRNG extends RNGInitAdapter {
         }
     }
 
-    private static long findSymbol(String symbol, DLLInfo dllInfo, boolean optional) {
-        long func = DLL.findSymbol(symbol, dllInfo.name, DLL.RegisteredNativeSymbol.any());
+    private static DLL.SymbolHandle findSymbol(String symbol, DLLInfo dllInfo, boolean optional) {
+        DLL.SymbolHandle func = DLL.findSymbol(symbol, dllInfo.name, DLL.RegisteredNativeSymbol.any());
         if (func == DLL.SYMBOL_NOT_FOUND) {
             if (!optional) {
                 throw RError.error(RError.NO_CALLER, RError.Message.RNG_SYMBOL, symbol);
             } else {
-                return 0;
+                return null;
             }
         } else {
             return func;
-- 
GitLab