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 c87b109962beea40b11379625d435d8f2d306083..728a1efd4b830abf09db8db075cd947356ce93ed 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
@@ -26,6 +26,7 @@ import com.oracle.truffle.r.runtime.data.RPairList;
 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.NativeCallInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
@@ -63,7 +64,7 @@ public class RGraphics {
                 DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
                 DLL.SymbolHandle func = DLL.findSymbol("InitGraphics", null, rns);
                 assert func != DLL.SYMBOL_NOT_FOUND;
-                RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(func, "InitGraphics", new Object[0]);
+                RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(new NativeCallInfo("InitGraphics", func, DLL.findLibrary("graphics")), new Object[0]);
             }
         }
     }
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 6ef837a03377c39f4a01d04bac0fda92dc9f8f01..9edab7fbd30972db49f6a3a5f47d2996403c446e 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
@@ -175,7 +175,7 @@ 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().asAddress());
+            DLL.DLLInfo dllInfo = (DLLInfo) externalPtr.getExternalObject();
             if (dllInfo == null) {
                 throw RError.error(this, RError.Message.REQUIRES_NAME_DLLINFO);
             }
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 ff6b649c54db7750cb1d0cfdb83207c2db2e2006..7b1275c1b1d5ffbe7a3539868b2d97a1a451e9a4 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
@@ -66,6 +66,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 
 /**
  * Private, undocumented, {@code .Internal} and {@code .Primitive} functions transcribed from GnuR,
@@ -285,7 +286,7 @@ public class HiddenInternalFunctions {
         @TruffleBoundary
         protected RList getRegisteredRoutines(RExternalPtr externalPtr) {
             Object[] data = new Object[NAMES.getLength()];
-            DLL.DLLInfo dllInfo = DLL.getDLLInfoForId((int) externalPtr.getAddr().asAddress());
+            DLL.DLLInfo dllInfo = (DLLInfo) externalPtr.getExternalObject();
             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 1b416abe220f39e0cec57644a8eeef84eb4e6884..8009ea798359a524bc8b59bd25bdd0408fbe1d0e 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
@@ -14,26 +14,19 @@ package com.oracle.truffle.r.nodes.builtin.base.foreign;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
-import java.util.Arrays;
-
 import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
-import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
-import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -42,8 +35,8 @@ 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;
+import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 
 /**
  * {@code .C} functions.
@@ -65,8 +58,11 @@ public abstract class DotC extends RBuiltinNode {
     private static final int VECTOR_LOGICAL = 12;
     @SuppressWarnings("unused") private static final int VECTOR_STRING = 12;
 
-    @Child private ExtractVectorNode nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-    @Child private ExtractVectorNode addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+    @Child private ExtractNativeCallInfoNode extractSymbolInfoNode = ExtractNativeCallInfoNodeGen.create();
+
+    protected NativeCallInfo extractSymbolInfo(VirtualFrame frame, RList symbol) {
+        return (NativeCallInfo) extractSymbolInfoNode.execute(frame, symbol);
+    }
 
     @Override
     public Object[] getDefaultParameterValues() {
@@ -76,9 +72,8 @@ 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) {
-        SymbolHandle handle = getAddressFromSymbolInfo(frame, symbol);
-        String name = getNameFromSymbolInfo(frame, symbol);
-        return dispatch(this, handle, name, naok, dup, args);
+        NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+        return dispatch(this, nativeCallInfo, naok, dup, args);
     }
 
     @SuppressWarnings("unused")
@@ -99,23 +94,7 @@ public abstract class DotC extends RBuiltinNode {
             errorProfile.enter();
             throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, f);
         }
-        return dispatch(this, func, f.getDataAt(0), naok, dup, args);
-    }
-
-    private String getNameFromSymbolInfo(VirtualFrame frame, RList symbol) {
-        if (nameExtract == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-        }
-        return RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
-    }
-
-    private SymbolHandle getAddressFromSymbolInfo(VirtualFrame frame, RList symbol) {
-        if (addressExtract == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-        }
-        return ((RExternalPtr) addressExtract.applyAccessField(frame, symbol, "address")).getAddr();
+        return dispatch(this, new NativeCallInfo(f.getDataAt(0), func, rns.getDllInfo()), naok, dup, args);
     }
 
     private static int[] checkNAs(RBuiltinNode node, int argIndex, int[] data) {
@@ -151,7 +130,7 @@ public abstract class DotC extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    protected static RList dispatch(RBuiltinNode node, SymbolHandle handle, String name, byte naok, byte dup, RArgsValuesAndNames args) {
+    protected static RList dispatch(RBuiltinNode node, NativeCallInfo nativeCallInfo, byte naok, byte dup, RArgsValuesAndNames args) {
         @SuppressWarnings("unused")
         boolean dupArgs = RRuntime.fromLogical(dup);
         @SuppressWarnings("unused")
@@ -191,10 +170,7 @@ public abstract class DotC extends RBuiltinNode {
                 throw RError.error(node, RError.Message.UNIMPLEMENTED_ARG_TYPE, i + 1);
             }
         }
-        if (FastROptions.TraceNativeCalls.getBooleanValue()) {
-            trace(name, nativeArgs);
-        }
-        RFFIFactory.getRFFI().getCRFFI().invoke(handle, nativeArgs);
+        RFFIFactory.getRFFI().getCRFFI().invoke(nativeCallInfo, nativeArgs);
         // we have to assume that the native method updated everything
         RStringVector listNames = validateArgNames(array.length, args.getSignature());
         Object[] results = new Object[array.length];
@@ -236,8 +212,4 @@ public abstract class DotC extends RBuiltinNode {
         return RDataFactory.createList(results, listNames);
     }
 
-    @TruffleBoundary
-    private static void trace(String name, Object[] nativeArgs) {
-        System.out.println("calling " + name + ": " + Arrays.toString(nativeArgs));
-    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ExtractNativeCallInfoNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ExtractNativeCallInfoNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..47d1f4a19c04070de6ce485cc2b780ee8f2bca86
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ExtractNativeCallInfoNode.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 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.nodes.builtin.base.foreign;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
+import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RExternalPtr;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RLogical;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+
+/**
+ * Extracts the salient information needed for a native call from the {@link RList} value provided
+ * from R.
+ */
+public abstract class ExtractNativeCallInfoNode extends Node {
+    @Child private ExtractVectorNode nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+    @Child private ExtractVectorNode addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+    @Child private ExtractVectorNode packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+    @Child private ExtractVectorNode infoExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+
+    protected abstract Object execute(VirtualFrame frame, RList symbol);
+
+    @Specialization
+    protected Object extractNativeCallInfo(VirtualFrame frame, RList symbol) {
+        if (nameExtract == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+        }
+        if (addressExtract == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+        }
+        if (packageExtract == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+        }
+        String name = RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
+        SymbolHandle address = ((RExternalPtr) addressExtract.applyAccessField(frame, symbol, "address")).getAddr();
+        // field name may be "package" or "dll", but always at (R) index 3
+        RList packageList = (RList) packageExtract.apply(frame, symbol, new Object[]{3}, RLogical.valueOf(false), RMissing.instance);
+        DLLInfo dllInfo = (DLLInfo) ((RExternalPtr) addressExtract.applyAccessField(frame, packageList, "info")).getExternalObject();
+        return new NativeCallInfo(name, address, dllInfo);
+
+    }
+
+}
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 eb498d9e37e77a4be870105a079948f5334602fd..5af4eaa4c4ebf20741417d091c2001dca1ac4737 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
@@ -16,7 +16,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
@@ -84,8 +83,6 @@ import com.oracle.truffle.r.library.utils.ObjectSizeNodeGen;
 import com.oracle.truffle.r.library.utils.RprofNodeGen;
 import com.oracle.truffle.r.library.utils.RprofmemNodeGen;
 import com.oracle.truffle.r.library.utils.TypeConvertNodeGen;
-import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
-import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode;
@@ -100,14 +97,13 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RList;
 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;
+import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 
 /**
  * {@code .Call} {@code .Fortran}, {@code .External}, {@code .External2}, {@code External.graphics}
@@ -194,23 +190,10 @@ public class ForeignFunctions {
             throw RError.nyi(this, getRBuiltin().name() + " specialization failure: " + (name == null ? "<unknown>" : name));
         }
 
-        @Child private ExtractVectorNode nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-        @Child private ExtractVectorNode addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+        @Child private ExtractNativeCallInfoNode extractSymbolInfoNode = ExtractNativeCallInfoNodeGen.create();
 
-        protected String getNameFromSymbolInfo(VirtualFrame frame, RList symbol) {
-            if (nameExtract == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-            }
-            return RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
-        }
-
-        protected SymbolHandle getAddressFromSymbolInfo(VirtualFrame frame, RList symbol) {
-            if (addressExtract == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-            }
-            return ((RExternalPtr) addressExtract.applyAccessField(frame, symbol, "address")).getAddr();
+        protected NativeCallInfo extractSymbolInfo(VirtualFrame frame, RList symbol) {
+            return (NativeCallInfo) extractSymbolInfoNode.execute(frame, symbol);
         }
 
         protected String checkPackageArg(Object rPackage, BranchProfile errorProfile) {
@@ -266,7 +249,8 @@ public class ForeignFunctions {
         @Specialization(guards = "lookupBuiltin(symbol) == null")
         protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, @SuppressWarnings("unused") Object rPackage,
                         @SuppressWarnings("unused") RMissing encoding) {
-            return DotC.dispatch(this, getAddressFromSymbolInfo(frame, symbol), getNameFromSymbolInfo(frame, symbol), naok, dup, args);
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            return DotC.dispatch(this, nativeCallInfo, naok, dup, args);
         }
 
         @Specialization
@@ -279,7 +263,7 @@ public class ForeignFunctions {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, f);
             }
-            return DotC.dispatch(this, func, f.getDataAt(0), naok, dup, args);
+            return DotC.dispatch(this, new NativeCallInfo(f.getDataAt(0), func, rns.getDllInfo()), naok, dup, args);
         }
 
         @SuppressWarnings("unused")
@@ -570,7 +554,8 @@ public class ForeignFunctions {
 
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(getAddressFromSymbolInfo(frame, symbol), getNameFromSymbolInfo(frame, symbol), args.getArguments());
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, args.getArguments());
         }
 
         @Specialization
@@ -586,7 +571,7 @@ public class ForeignFunctions {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(func, name, args.getArguments());
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), args.getArguments());
         }
 
         @Fallback
@@ -655,9 +640,9 @@ public class ForeignFunctions {
 
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            String name = getNameFromSymbolInfo(frame, symbol);
-            Object list = encodeArgumentPairList(args, name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(getAddressFromSymbolInfo(frame, symbol), name, new Object[]{list});
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            Object list = encodeArgumentPairList(args, nativeCallInfo.name);
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, new Object[]{list});
         }
 
         @Specialization
@@ -674,7 +659,7 @@ public class ForeignFunctions {
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
             Object list = encodeArgumentPairList(args, name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(func, name, new Object[]{list});
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{list});
         }
 
         @Fallback
@@ -727,10 +712,10 @@ public class ForeignFunctions {
 
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            String name = getNameFromSymbolInfo(frame, symbol);
-            Object list = encodeArgumentPairList(args, name);
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            Object list = encodeArgumentPairList(args, nativeCallInfo.name);
             // TODO: provide proper values for the CALL, OP and RHO parameters
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(getAddressFromSymbolInfo(frame, symbol), name, new Object[]{CALL, OP, list, RHO});
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, new Object[]{CALL, OP, list, RHO});
         }
 
         @Specialization
@@ -748,7 +733,7 @@ public class ForeignFunctions {
             }
             Object list = encodeArgumentPairList(args, name);
             // TODO: provide proper values for the CALL, OP and RHO parameters
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(func, name, new Object[]{CALL, OP, list, RHO});
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{CALL, OP, list, RHO});
         }
 
         @Fallback
@@ -786,9 +771,9 @@ public class ForeignFunctions {
 
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            String name = getNameFromSymbolInfo(frame, symbol);
-            Object list = encodeArgumentPairList(args, name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(getAddressFromSymbolInfo(frame, symbol), name, new Object[]{list});
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            Object list = encodeArgumentPairList(args, nativeCallInfo.name);
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, new Object[]{list});
         }
 
         @Specialization
@@ -805,7 +790,7 @@ public class ForeignFunctions {
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
             Object list = encodeArgumentPairList(args, name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(func, name, new Object[]{list});
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{list});
         }
 
         @Fallback
@@ -843,7 +828,8 @@ public class ForeignFunctions {
 
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(getAddressFromSymbolInfo(frame, symbol), getNameFromSymbolInfo(frame, symbol), args.getArguments());
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, args.getArguments());
         }
 
         @Specialization
@@ -860,7 +846,7 @@ public class ForeignFunctions {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(func, name, args.getArguments());
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), args.getArguments());
         }
 
         @Fallback
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 5abe50b8ca4352f2df4438e4c29968208b36480e..4b79d033cce8889333b8b758dd31c16793a9f3a2 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
@@ -25,10 +25,11 @@ package com.oracle.truffle.r.runtime.ffi.generic;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.GridRFFI;
 import com.oracle.truffle.r.runtime.ffi.LibPaths;
+import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 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 {
@@ -65,12 +66,12 @@ public class Generic_Grid implements GridRFFI {
     @Override
     public Object initGrid(REnvironment gridEvalEnv) {
         long initGrid = GridProvider.gridProvider().getInitGrid();
-        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new SymbolHandle(initGrid), "L_initGrid", new Object[]{gridEvalEnv});
+        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo("L_initGrid", new SymbolHandle(initGrid), DLL.findLibrary("grid")), new Object[]{gridEvalEnv});
     }
 
     @Override
     public Object killGrid() {
         long killGrid = GridProvider.gridProvider().getKillGrid();
-        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new SymbolHandle(killGrid), "L_killGrid", new Object[0]);
+        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo("L_killGrid", new SymbolHandle(killGrid), DLL.findLibrary("grid")), 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 a97616f45fb2bed16b716055223c688bd046dcb9..fedd559f04c17749c46c8744e7379ad5b360870e 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
@@ -33,6 +33,7 @@ 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.NativeCallInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
 
@@ -71,7 +72,7 @@ public class Generic_Tools implements ToolsRFFI {
         try {
             parseRdCritical.acquire();
             long parseRd = ToolsProvider.toolsProvider().getParseRd();
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new SymbolHandle(parseRd), ToolsProvider.C_PARSE_RD,
+            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo("parseRd", new SymbolHandle(parseRd), DLL.findLibrary("tools")),
                             new Object[]{con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups});
         } catch (Throwable ex) {
             throw RInternalError.shouldNotReachHere(ex, "error during Rd parsing");
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 174ad3844f5924b609eb0e6a860e3b964e9ac95c..1928c09f73d4053f518cb777a1c8257b78451ae6 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
@@ -22,9 +22,12 @@
  */
 package com.oracle.truffle.r.runtime.ffi.jni;
 
+import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCall;
+import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceEnabled;
+
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 
 public class JNI_C implements CRFFI {
 
@@ -36,8 +39,11 @@ public class JNI_C implements CRFFI {
      */
     @Override
     @TruffleBoundary
-    public synchronized void invoke(SymbolHandle symbolHandle, Object[] args) {
-        c(symbolHandle.asAddress(), args);
+    public synchronized void invoke(NativeCallInfo nativeCallInfo, Object[] args) {
+        if (traceEnabled()) {
+            traceDownCall(nativeCallInfo.name, args);
+        }
+        c(nativeCallInfo.address.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 16aabaea923d0440f3edb434c60f8a28d246897a..8ea6fac033712f9b115c3e191aef0d82a5b8b606 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
@@ -31,9 +31,9 @@ import com.oracle.truffle.r.runtime.RInternalError;
 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.NativeCallInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
 
@@ -91,11 +91,11 @@ public class JNI_Call implements CallRFFI {
 
     @Override
     @TruffleBoundary
-    public synchronized Object invokeCall(SymbolHandle handleArg, String name, Object[] args) {
-        long address = handleArg.asAddress();
+    public synchronized Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args) {
+        long address = nativeCallInfo.address.asAddress();
         Object result = null;
         if (traceEnabled()) {
-            traceDownCall(name, args);
+            traceDownCall(nativeCallInfo.name, args);
         }
         try {
             switch (args.length) {
@@ -117,7 +117,7 @@ public class JNI_Call implements CallRFFI {
             return result;
         } finally {
             if (traceEnabled()) {
-                traceDownCallReturn(name, result);
+                traceDownCallReturn(nativeCallInfo.name, result);
             }
         }
     }
@@ -152,11 +152,11 @@ public class JNI_Call implements CallRFFI {
 
     @Override
     @TruffleBoundary
-    public synchronized void invokeVoidCall(SymbolHandle handle, String name, Object[] args) {
+    public synchronized void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args) {
         if (traceEnabled()) {
-            traceDownCall(name, args);
+            traceDownCall(nativeCallInfo.name, args);
         }
-        long address = handle.asAddress();
+        long address = nativeCallInfo.address.asAddress();
         try {
             switch (args.length) {
                 case 0:
@@ -170,7 +170,7 @@ public class JNI_Call implements CallRFFI {
             }
         } finally {
             if (traceEnabled()) {
-                traceDownCallReturn(name, null);
+                traceDownCallReturn(nativeCallInfo.name, null);
             }
         }
     }
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 2932ecbe2b7370e072093700217529e960a6a3c1..eddf195c7b72b93340f887cd8441f302b5ddebf0 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
@@ -26,12 +26,22 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
 /**
- * The rarely seen {@code externalptr} type.
+ * The rarely seen {@code externalptr} type used in native code.
  */
 public class RExternalPtr extends RAttributeStorage implements RTypedValue {
+    /**
+     * In GNU R, typically the address of some C structure, so a {@code void*}. Represented here as
+     * our abstraction of a "native symbol" (even though there may not actually be a symbol
+     * associated with the address).
+     */
     private SymbolHandle handle;
     private Object tag;
     private Object prot;
+    /**
+     * Has no GNU R counterpart. Used internally to store a Java object that, for example,
+     * corresponds to the C state in {@link #handle}. Evidently, the R FFI never accesses this
+     * field.
+     */
     private Object externalObject;
 
     RExternalPtr(SymbolHandle handle, Object externalObject, Object tag, Object prot) {
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 a1b7d4fc55642302da0272f420c31208cb96f289..24cdcd702ad4a17447951e0f3aff6fbf9f5267fc 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
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-
 /**
  * Support for the {.C} and {.Fortran} calls.
  */
@@ -32,9 +30,6 @@ public interface CRFFI {
      * Invoke the native method identified by {@code symbolInfo} passing it the arguments in
      * {@code args}. The values in {@code args} should be native types,e.g., {@code double[]} not
      * {@code RDoubleVector}.
-     *
-     * @param handle of the native method
-     * @param args native arguments
      */
-    void invoke(SymbolHandle handle, Object[] args);
+    void invoke(NativeCallInfo nativeCallInfo, 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 6baeebaae6ed0b53e3d4f3d831458c8183eb6030..3029ffce07e33bfd27552919f3916437fb3a93d3 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,8 +22,6 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-
 /**
  * Support for the {.Call} and {.External} calls.
  */
@@ -32,17 +30,13 @@ public interface CallRFFI {
      * Invoke the native function identified by {@code symbolInfo} passing it the arguments in
      * {@code args}. The values in {@code args} can be any of the types used to represent {@code R}
      * values in the implementation.
-     *
-     * @param handle the address of the native function
-     * @param name the name of the native function
-     * @param args arguments
      */
-    Object invokeCall(SymbolHandle handle, String name, Object[] args);
+    Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args);
 
     /**
      * Variant that does not return a result (primarily for library "init" methods).
      */
-    void invokeVoidCall(SymbolHandle handle, String name, Object[] args);
+    void invokeVoidCall(NativeCallInfo nativeCallInfo, 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 ec74693d7f5d5723b403d4a722dbb2a58efa47a0..bceaacfbd4e212370d6dd05252803756e897201e 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
@@ -30,6 +30,7 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
@@ -188,16 +189,16 @@ public class DLL {
             data[0] = name;
             data[1] = path;
             data[2] = RRuntime.asLogical(dynamicLookup);
-            data[3] = createExternalPtr(new SymbolHandle(new Long(System.identityHashCode(handle))), HANDLE_CLASS);
+            data[3] = createExternalPtr(new SymbolHandle(new Long(System.identityHashCode(handle))), HANDLE_CLASS, handle);
             /*
-             * 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.
+             * GnuR sets the info member to an externalptr whose value is the C DllInfo structure
+             * itself. We use the internal "externalObject" slot instead, and we use the "id" for
+             * the "addr" slot.
              */
-            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;
+            data[4] = createExternalPtr(new SymbolHandle(new Long(id)), INFO_REFERENCE_CLASS, this);
+            RList result = RDataFactory.createList(data, DLLInfo.NAMES);
+            result.setClassAttr(RDataFactory.createStringVectorFromScalar(DLLINFO_CLASS));
+            return result;
         }
 
         @Override
@@ -241,11 +242,11 @@ public class DLL {
                 /*
                  * GnuR stores this as an externalptr whose value is the C RegisteredNativeType
                  * struct. We can't do that, and it's not clear any code uses that fact, so we
-                 * stored the registered address.
+                 * stored the registered address. TODO use externalObject slot?
                  */
-                data[1] = DLL.createExternalPtr(rnt.dotSymbol.fun, REGISTERED_NATIVE_SYMBOL_CLASS);
+                data[1] = DLL.createExternalPtr(rnt.dotSymbol.fun, REGISTERED_NATIVE_SYMBOL_CLASS, null);
             } else {
-                data[1] = DLL.createExternalPtr(address, NATIVE_SYMBOL_CLASS);
+                data[1] = DLL.createExternalPtr(address, NATIVE_SYMBOL_CLASS, null);
             }
             data[2] = libInfo.toRList();
             if (n > 3) {
@@ -288,23 +289,14 @@ public class DLL {
 
     public static final SymbolHandle SYMBOL_NOT_FOUND = null;
 
-    public static synchronized DLLInfo getDLLInfoForId(int id) {
-        for (DLLInfo dllInfo : list) {
-            if (dllInfo.id == id) {
-                return dllInfo;
-            }
-        }
-        return null;
-    }
-
     public static boolean isDLLInfo(RExternalPtr info) {
         RSymbol tag = (RSymbol) info.getTag();
         return tag.getName().equals(DLLInfo.DLL_INFO_REFERENCE);
     }
 
-    public static RExternalPtr createExternalPtr(SymbolHandle value, RStringVector rClass) {
+    public static RExternalPtr createExternalPtr(SymbolHandle value, RStringVector rClass, Object externalObject) {
         CompilerAsserts.neverPartOfCompilation(); // for interning
-        RExternalPtr result = RDataFactory.createExternalPtr(value, RDataFactory.createSymbolInterned(rClass.getDataAt(0)));
+        RExternalPtr result = RDataFactory.createExternalPtr(value, externalObject, RDataFactory.createSymbolInterned(rClass.getDataAt(0)), RNull.instance);
         result.setClassAttr(rClass);
         return result;
     }
@@ -363,7 +355,7 @@ public class DLL {
         if (initFunc != SYMBOL_NOT_FOUND) {
             synchronized (DLL.class) {
                 try {
-                    RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(initFunc, pkgInit, new Object[]{dllInfo});
+                    RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(new NativeCallInfo(pkgInit, initFunc, dllInfo), new Object[]{dllInfo});
                 } catch (ReturnException ex) {
                     // An error call can, due to condition handling, throw this which we must
                     // propogate
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2559c719ee30f9e3880a1016448c05b851d2f01
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallInfo.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, 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.api.CompilerDirectives.ValueType;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+
+/**
+ * The salient information needed for a native call extracted from the {@link RList} object passed
+ * by R.
+ */
+@ValueType
+public final class NativeCallInfo {
+    public final String name;
+    public final SymbolHandle address;
+    public final DLLInfo dllInfo;
+
+    public NativeCallInfo(String name, SymbolHandle address, DLLInfo dllInfo) {
+        this.name = name;
+        this.address = address;
+        this.dllInfo = dllInfo;
+    }
+}