diff --git a/ci.hocon b/ci.hocon
index f274b102ffab633d0266a478af40497b0283a00e..4c97461fc140d1de63becdf5323cd0dcb8e08801 100644
--- a/ci.hocon
+++ b/ci.hocon
@@ -146,7 +146,7 @@ gateTestLinuxLLVM : ${common} ${requireGCC} {
   environment :  {
       TZDIR: "/usr/share/zoneinfo"
       FASTR_RFFI : "llvm"
-      FASTR_LLVM_HOME : "$DRAGONEGG_LLVM/bin"
+      FASTR_LLVM_TOOLS : "$DRAGONEGG_LLVM/bin"
       FASTR_LLVM_GFORTRAN_LLVM_AS : "$DRAGONEGG_LLVM/bin/llvm-as"
       FASTR_LLVM_GFORTRAN : "$DRAGONEGG_GCC/bin/gfortran"
       FASTR_LLVM_DRAGONEGG : "$DRAGONEGG_GCC/lib/dragonegg.so"
@@ -192,7 +192,7 @@ gateTestDarwinLLVM: ${common} ${darwinEnvironment} ${requireGCC} {
 
   environment :  {
       FASTR_RFFI : "llvm"
-      FASTR_LLVM_HOME : "$DRAGONEGG_LLVM/bin"
+      FASTR_LLVM_TOOLS : "$DRAGONEGG_LLVM/bin"
       FASTR_LLVM_GFORTRAN_LLVM_AS : "$DRAGONEGG_LLVM/bin/llvm-as"
       FASTR_LLVM_GFORTRAN : "$DRAGONEGG_GCC/bin/gfortran"
       FASTR_LLVM_DRAGONEGG : "$DRAGONEGG_GCC/lib/dragonegg.so"
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index c7984a2e4953a5c1b80e11efebc6db76bc7f5180..523b80e3b1e3fd1e07026931e2e2f47a1c1caffa 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -31,7 +31,6 @@ import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
@@ -234,18 +233,14 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     @Override
     @TruffleBoundary
-    public Object R_getClassDef(String clazz) {
-        String name = "getClassDef";
-        RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
-        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), true, null, clazz);
+    public Object R_getClassDef(Object clazz) {
+        throw implementedAsNode();
     }
 
     @Override
     @TruffleBoundary
-    public Object R_do_MAKE_CLASS(String clazz) {
-        String name = "getClass";
-        RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
-        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), true, null, clazz);
+    public Object R_do_MAKE_CLASS(Object clazz) {
+        throw implementedAsNode();
     }
 
     @Override
@@ -1517,48 +1512,10 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         }
     }
 
-    private static HashMap<String, Integer> name2typeTable;
-
-    static {
-        name2typeTable = new HashMap<>(26);
-        name2typeTable.put("NULL", SEXPTYPE.NILSXP.code);
-        /* real types */
-        name2typeTable.put("symbol", SEXPTYPE.SYMSXP.code);
-        name2typeTable.put("pairlist", SEXPTYPE.LISTSXP.code);
-        name2typeTable.put("closure", SEXPTYPE.CLOSXP.code);
-        name2typeTable.put("environment", SEXPTYPE.ENVSXP.code);
-        name2typeTable.put("promise", SEXPTYPE.PROMSXP.code);
-        name2typeTable.put("language", SEXPTYPE.LANGSXP.code);
-        name2typeTable.put("special", SEXPTYPE.SPECIALSXP.code);
-        name2typeTable.put("builtin", SEXPTYPE.BUILTINSXP.code);
-        name2typeTable.put("char", SEXPTYPE.CHARSXP.code);
-        name2typeTable.put("logical", SEXPTYPE.LGLSXP.code);
-        name2typeTable.put("integer", SEXPTYPE.INTSXP.code);
-        name2typeTable.put("double", SEXPTYPE.REALSXP.code);
-        /*-  "real", for R <= 0.61.x */
-        name2typeTable.put("complex", SEXPTYPE.CPLXSXP.code);
-        name2typeTable.put("character", SEXPTYPE.STRSXP.code);
-        name2typeTable.put("...", SEXPTYPE.DOTSXP.code);
-        name2typeTable.put("any", SEXPTYPE.ANYSXP.code);
-        name2typeTable.put("expression", SEXPTYPE.EXPRSXP.code);
-        name2typeTable.put("list", SEXPTYPE.VECSXP.code);
-        name2typeTable.put("externalptr", SEXPTYPE.EXTPTRSXP.code);
-        name2typeTable.put("bytecode", SEXPTYPE.BCODESXP.code);
-        name2typeTable.put("weakref", SEXPTYPE.WEAKREFSXP.code);
-        name2typeTable.put("raw", SEXPTYPE.RAWSXP.code);
-        name2typeTable.put("S4", SEXPTYPE.S4SXP.code);
-        name2typeTable.put("numeric", SEXPTYPE.REALSXP.code);
-        name2typeTable.put("name", SEXPTYPE.SYMSXP.code);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int Rf_str2type(String name) {
-        if (name == null) {
-            return -1;
-        }
-        Integer result = name2typeTable.get(name);
-        return result != null ? result : -1;
+    @Override
+    @TruffleBoundary
+    public int Rf_str2type(Object name) {
+        throw implementedAsNode();
     }
 
     @Override
@@ -1949,7 +1906,8 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
             protected Object access(VectorWrapper receiver, Object[] arguments) {
                 try {
-                    // Currently, there is only one "executable" object, which is CharSXPWrapper.
+                    // Currently, there is only one "executable" object, which is
+                    // CharSXPWrapper.
                     // See CharSXPWrapperMR for the EXECUTABLE message handler.
                     assert arguments.length == 0 && receiver.vector instanceof CharSXPWrapper;
                     return ForeignAccess.sendExecute(execMsg, receiver.vector);
@@ -1972,7 +1930,22 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         private final TruffleObject vector;
 
         public VectorWrapper(TruffleObject vector) {
+            assert vector instanceof RObject;
             this.vector = vector;
+            NativeDataAccess.setNativeWrapper((RObject) vector, this);
+        }
+
+        static Object get(TruffleObject x) {
+            assert x instanceof RObject;
+            Object wrapper = NativeDataAccess.getNativeWrapper((RObject) x);
+            if (wrapper != null) {
+                return wrapper;
+            } else {
+                wrapper = new VectorWrapper(x);
+                // Establish the 1-1 relationship between the object and its native wrapper
+                NativeDataAccess.setNativeWrapper((RObject) x, wrapper);
+                return wrapper;
+            }
         }
 
         public TruffleObject getVector() {
@@ -1983,38 +1956,44 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         public ForeignAccess getForeignAccess() {
             return VectorWrapperMRForeign.ACCESS;
         }
+
+        @Override
+        public int hashCode() {
+            return vector.hashCode();
+        }
+
     }
 
     @Override
     public Object INTEGER(Object x) {
         // also handles LOGICAL
         assert x instanceof RIntVector || x instanceof RLogicalVector || x == RNull.instance;
-        return new VectorWrapper(guaranteeVectorOrNull(x, RVector.class));
+        return VectorWrapper.get(guaranteeVectorOrNull(x, RVector.class));
     }
 
     @Override
     public Object LOGICAL(Object x) {
-        return new VectorWrapper(guaranteeVectorOrNull(x, RLogicalVector.class));
+        return VectorWrapper.get(guaranteeVectorOrNull(x, RLogicalVector.class));
     }
 
     @Override
     public Object REAL(Object x) {
-        return new VectorWrapper(guaranteeVectorOrNull(x, RDoubleVector.class));
+        return VectorWrapper.get(guaranteeVectorOrNull(x, RDoubleVector.class));
     }
 
     @Override
     public Object RAW(Object x) {
-        return new VectorWrapper(guaranteeVectorOrNull(x, RRawVector.class));
+        return VectorWrapper.get(guaranteeVectorOrNull(x, RRawVector.class));
     }
 
     @Override
     public Object COMPLEX(Object x) {
-        return new VectorWrapper(guaranteeVectorOrNull(x, RComplexVector.class));
+        return VectorWrapper.get(guaranteeVectorOrNull(x, RComplexVector.class));
     }
 
     @Override
     public Object R_CHAR(Object x) {
-        return new VectorWrapper(guaranteeVectorOrNull(x, CharSXPWrapper.class));
+        return VectorWrapper.get(guaranteeVectorOrNull(x, CharSXPWrapper.class));
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java
index 19ebc60087b43aa9e717c0a82e3ff6f7027e67be..fc661a180f319a6b2b04c8bccec9318a9bd04788 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -23,10 +23,5 @@
 /**
  * A collection of types and {@link com.oracle.truffle.api.interop.MessageResolution} classes that
  * support the implementations.
- *
- * See {@link com.oracle.truffle.r.ffi.impl.interop.base} and
- * {@link com.oracle.truffle.r.ffi.impl.interop.pcre} for similar classes specific to the
- * {@link com.oracle.truffle.r.runtime.ffi.BaseRFFI} and
- * {@link com.oracle.truffle.r.runtime.ffi.PCRERFFI} interfaces.
  */
 package com.oracle.truffle.r.ffi.impl.interop;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
index 1075ab3f6368df16c2638431abd54e1193c5e20b..27448accd62d39405390e1353a3fe5ea079a1d5f 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java
@@ -41,6 +41,7 @@ import com.oracle.truffle.r.ffi.impl.llvm.upcalls.BytesToNativeCharArrayCall;
 import com.oracle.truffle.r.ffi.impl.llvm.upcalls.CharSXPToNativeArrayCall;
 import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks;
 import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode;
+import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -162,12 +163,12 @@ final class TruffleLLVM_Call implements CallRFFI {
 
         @Specialization
         protected static Object convert(int value) {
-            return RDataFactory.createIntVector(new int[]{value}, RRuntime.isNA(value));
+            return RDataFactory.createIntVector(new int[]{value}, !RRuntime.isNA(value));
         }
 
         @Specialization
         protected static Object convert(double value) {
-            return RDataFactory.createDoubleVector(new double[]{value}, RRuntime.isNA(value));
+            return RDataFactory.createDoubleVector(new double[]{value}, !RRuntime.isNA(value));
         }
 
         @Specialization
@@ -182,12 +183,12 @@ final class TruffleLLVM_Call implements CallRFFI {
 
         @Specialization
         protected static Object convert(byte value) {
-            return RDataFactory.createLogicalVector(new byte[]{value}, RRuntime.isNA(value));
+            return RDataFactory.createLogicalVector(new byte[]{value}, !RRuntime.isNA(value));
         }
 
         @Specialization
         protected static Object convert(String value) {
-            return RDataFactory.createStringVector(new String[]{value}, RRuntime.isNA(value));
+            return RDataFactory.createStringVector(new String[]{value}, !RRuntime.isNA(value));
         }
 
         @Fallback
@@ -259,6 +260,14 @@ final class TruffleLLVM_Call implements CallRFFI {
                 return result;
             } catch (InteropException ex) {
                 throw RInternalError.shouldNotReachHere(ex);
+            } catch (Exception ex) {
+                if (ex.getCause() instanceof RError) {
+                    // Sulong wraps an error having occurred in an upcall, so let's propagate the
+                    // wrapped one instead of the Sulong one.
+                    throw (RError) ex.getCause();
+                } else {
+                    throw ex;
+                }
             } finally {
                 RContext.getRForeignAccessFactory().setIsNull(isNullSetting);
             }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java
index 568b273a72b0de402d520a02798a4940a67f643b..f934408376f508f80b0035af089d84c9f1622f2f 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java
@@ -23,14 +23,22 @@
 package com.oracle.truffle.r.ffi.impl.llvm;
 
 import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.PrintStream;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
@@ -39,6 +47,8 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RPlatform;
+import com.oracle.truffle.r.runtime.RPlatform.OSInfo;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.ffi.DLL;
@@ -63,6 +73,18 @@ import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
  *
  */
 public class TruffleLLVM_DLL implements DLLRFFI {
+    /*
+     * The LIBS file, which is included in the LLVM archive, enumerates native dynamic libraries to
+     * be linked with the LLVM library in the archive.
+     */
+    private static final String LIBS = "LIBS";
+
+    private static final Set<String> ignoredNativeLibs = new HashSet<>();
+    static {
+        ignoredNativeLibs.add("Rblas");
+        ignoredNativeLibs.add("Rlapack");
+    }
+
     static class ContextStateImpl implements RContext.ContextState {
         /**
          * When a new {@link RContext} is created we have to re-parse the libR modules,
@@ -121,7 +143,19 @@ public class TruffleLLVM_DLL implements DLLRFFI {
         boolean match(String name);
     }
 
-    public static LLVM_IR[] getZipLLVMIR(String path) {
+    public static final class LLVMArchive {
+        public final LLVM_IR[] irs;
+        public final List<String> nativeLibs;
+
+        private LLVMArchive(LLVM_IR[] irs, List<String> nativeLibs) {
+            super();
+            this.irs = irs;
+            this.nativeLibs = nativeLibs;
+        }
+    }
+
+    public static LLVMArchive getZipLLVMIR(String path) {
+        List<String> nativeLibs = Collections.emptyList();
         try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(path)))) {
             ArrayList<LLVM_IR> irList = new ArrayList<>();
             while (true) {
@@ -130,24 +164,28 @@ public class TruffleLLVM_DLL implements DLLRFFI {
                     break;
                 }
                 int size = (int) entry.getSize();
-                byte[] bc = new byte[size];
+                byte[] bytes = new byte[size];
                 int n;
                 int totalRead = 0;
-                while (totalRead < size && (n = zis.read(bc, totalRead, size - totalRead)) != -1) {
+                while (totalRead < size && (n = zis.read(bytes, totalRead, size - totalRead)) != -1) {
                     totalRead += n;
                 }
+                if (LIBS.equals(entry.getName())) {
+                    nativeLibs = getNativeLibs(bytes);
+                    continue;
+                }
                 Path zipName = Paths.get(entry.getName());
                 String name = zipName.getFileName().toString();
                 int ix = name.indexOf('.');
                 if (ix > 0) {
                     name = name.substring(0, ix);
                 }
-                LLVM_IR.Binary ir = new LLVM_IR.Binary(name, bc);
+                LLVM_IR.Binary ir = new LLVM_IR.Binary(name, bytes);
                 irList.add(ir);
                 // debugging
                 if (System.getenv("FASTR_LLVM_DEBUG") != null) {
                     try (FileOutputStream bs = new FileOutputStream(Paths.get("tmpzip", name).toString())) {
-                        bs.write(bc);
+                        bs.write(bytes);
                     }
                     try (PrintStream bs = new PrintStream(new FileOutputStream(Paths.get("tmpb64", name).toString()))) {
                         bs.print(ir.base64);
@@ -156,13 +194,24 @@ public class TruffleLLVM_DLL implements DLLRFFI {
             }
             LLVM_IR[] result = new LLVM_IR[irList.size()];
             irList.toArray(result);
-            return result;
+            return new LLVMArchive(result, nativeLibs);
         } catch (IOException ex) {
             // not a zip file
             return null;
         }
     }
 
+    private static List<String> getNativeLibs(byte[] bytes) throws IOException {
+        List<String> libs = new LinkedList<>();
+        try (BufferedReader libReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)))) {
+            String lib = null;
+            while ((lib = libReader.readLine()) != null) {
+                libs.add(lib);
+            }
+        }
+        return libs;
+    }
+
     private static class TruffleLLVM_DLOpenNode extends Node implements DLOpenNode {
         @Child private TruffleLLVM_NativeDLL.TruffleLLVM_NativeDLOpen nativeDLLOpenNode;
 
@@ -175,7 +224,8 @@ public class TruffleLLVM_DLL implements DLLRFFI {
         @Override
         public Object execute(String path, boolean local, boolean now) {
             try {
-                LLVM_IR[] irs = getZipLLVMIR(path);
+                LLVMArchive ar = getZipLLVMIR(path);
+                LLVM_IR[] irs = ar.irs;
                 if (irs == null) {
                     return tryOpenNative(path, local, now);
                 }
@@ -183,6 +233,8 @@ public class TruffleLLVM_DLL implements DLLRFFI {
                 if (libName.equals("libR")) {
                     // save for new RContexts
                     truffleDLL.libRModules = irs;
+                } else {
+                    loadNativeLibs(ar.nativeLibs);
                 }
                 for (LLVM_IR ir : irs) {
                     parseLLVM(libName, ir);
@@ -199,10 +251,22 @@ public class TruffleLLVM_DLL implements DLLRFFI {
                     sb.append(t.getMessage());
                     t = t.getCause();
                 }
+                ex.printStackTrace();
                 throw new UnsatisfiedLinkError(sb.toString());
             }
         }
 
+        private void loadNativeLibs(List<String> nativeLibs) {
+            OSInfo osInfo = RPlatform.getOSInfo();
+            for (String nativeLib : nativeLibs) {
+                if (ignoredNativeLibs.contains(nativeLib)) {
+                    continue;
+                }
+                String nativeLibName = "lib" + nativeLib + "." + osInfo.libExt;
+                tryOpenNative(nativeLibName, false, true);
+            }
+        }
+
         private long tryOpenNative(String path, boolean local, boolean now) throws UnsatisfiedLinkError {
             if (nativeDLLOpenNode == null) {
                 nativeDLLOpenNode = insert(new TruffleLLVM_NativeDLL.TruffleLLVM_NativeDLOpen());
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
index d6a1f4b67f5d8153fc01a3d1bf6abb775ef4b247..ad6eed382d4b3c7322dc5fbefc3d4fddc11ec70c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java
@@ -40,6 +40,7 @@ import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RScalar;
+import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.CEntry;
@@ -108,6 +109,8 @@ public class TruffleLLVM_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
             return RInteger.valueOf((int) x);
         } else if (x instanceof Byte) {
             return RLogical.valueOf((byte) x);
+        } else if (x instanceof String) {
+            return RString.valueOf((String) x);
         } else {
             throw RInternalError.shouldNotReachHere();
         }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.java
index 91acc85892f4595697ed8dc15351271b23478039..a606291213ba4c953413408904d4b63850e00cdb 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, 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
@@ -28,6 +28,7 @@ import java.io.OutputStream;
 
 import com.oracle.truffle.r.ffi.impl.llvm.LLVM_IR;
 import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_DLL;
+import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_DLL.LLVMArchive;
 import com.oracle.truffle.r.runtime.ProcessOutputManager;
 
 public class ShowLLVMIR {
@@ -64,7 +65,8 @@ public class ShowLLVMIR {
             usage();
         }
         try {
-            LLVM_IR[] irs = TruffleLLVM_DLL.getZipLLVMIR(objPath);
+            LLVMArchive ar = TruffleLLVM_DLL.getZipLLVMIR(objPath);
+            LLVM_IR[] irs = ar.irs;
             if (irs == null) {
                 System.out.printf("no llvm ir in %s\n", objPath);
                 System.exit(1);
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java
index dc51516b4fccfc8c95208324e32a5781c659ed12..96e7f6e18b8d8a2fc17ed4597feaf5211878d49b 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.nodes.Node;
 
 @MessageResolution(receiverType = BytesToNativeCharArrayCall.class)
 public class BytesToNativeCharArrayCallMR {
+
     @Resolve(message = "EXECUTE")
     public abstract static class BytesToNativeCharArrayCallExecute extends Node {
         protected java.lang.Object access(BytesToNativeCharArrayCall receiver, Object[] arguments) {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DoMakeClassNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DoMakeClassNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..1abceefaded81c425d756a971bee4a98a59e020b
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DoMakeClassNode.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.nodes;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+
+public abstract class DoMakeClassNode extends FFIUpCallNode.Arg1 {
+
+    public static DoMakeClassNode create() {
+        return DoMakeClassNodeGen.create();
+    }
+
+    @Specialization
+    @TruffleBoundary
+    Object handleString(Object cls, @Cached("create()") NativeStringCastNode nscn) {
+        String clazz = nscn.executeObject(cls);
+        String name = "getClass";
+        RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
+        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), true, null, clazz);
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/GetClassDefNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/GetClassDefNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..05f10669c977a2aa5206913e784749c7f3064553
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/GetClassDefNode.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.nodes;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+
+public abstract class GetClassDefNode extends FFIUpCallNode.Arg1 {
+
+    public static GetClassDefNode create() {
+        return GetClassDefNodeGen.create();
+    }
+
+    @Specialization
+    @TruffleBoundary
+    Object handleString(Object cls, @Cached("create()") NativeStringCastNode nscn) {
+        String clazz = nscn.executeObject(cls);
+        String name = "getClassDef";
+        RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
+        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), true, null, clazz);
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..92d7e734174965433a9a453dff0308b3106c4968
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.nodes;
+
+import static com.oracle.truffle.r.runtime.data.NativeDataAccess.readNativeString;
+
+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.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RInternalError;
+
+public abstract class NativeStringCastNode extends Node {
+
+    @Child private Node isPtrNode;
+
+    public static NativeStringCastNode create() {
+        return NativeStringCastNodeGen.create();
+    }
+
+    public abstract String executeObject(Object s);
+
+    @Specialization
+    @TruffleBoundary
+    String handleString(String s) {
+        return s;
+    }
+
+    protected static Node createAsPointerNode() {
+        return Message.AS_POINTER.createNode();
+    }
+
+    protected static Node createToNativeNode() {
+        return Message.TO_NATIVE.createNode();
+    }
+
+    protected boolean isPointerNode(TruffleObject s) {
+        if (isPtrNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            isPtrNode = insert(Message.IS_POINTER.createNode());
+        }
+        return ForeignAccess.sendIsPointer(isPtrNode, s);
+    }
+
+    @Specialization(guards = "isPointerNode(s)")
+    String handlePointerAddress(TruffleObject s, @Cached("createAsPointerNode()") Node sAsPtrNode) {
+        try {
+            return readNativeString(ForeignAccess.sendAsPointer(sAsPtrNode, s));
+        } catch (UnsupportedMessageException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+
+    @Specialization(guards = "!isPointerNode(s)")
+    String handleNonPointerAddress(TruffleObject s, @Cached("createToNativeNode()") Node sToNativeNode, @Cached("createAsPointerNode()") Node sAsPtrNode) {
+        try {
+            Object sNative = ForeignAccess.sendToNative(sToNativeNode, s);
+            return readNativeString(ForeignAccess.sendAsPointer(sAsPtrNode, (TruffleObject) sNative));
+        } catch (UnsupportedMessageException e) {
+            throw RInternalError.shouldNotReachHere(e);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NewCustomConnectionNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NewCustomConnectionNode.java
index dc8e816a7d5ae6cf967e8facb8c3683e1b13f0c8..6378bf00df6df13562e6ff0e3f66194cd0bfb477 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NewCustomConnectionNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NewCustomConnectionNode.java
@@ -22,19 +22,11 @@
  */
 package com.oracle.truffle.r.ffi.impl.nodes;
 
-import static com.oracle.truffle.r.runtime.data.NativeDataAccess.readNativeString;
-
 import java.io.IOException;
 
 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.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.Message;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.interop.UnsupportedMessageException;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.conn.ConnectionSupport.InvalidConnection;
 import com.oracle.truffle.r.runtime.conn.NativeConnections.NativeRConnection;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
@@ -47,36 +39,11 @@ public abstract class NewCustomConnectionNode extends FFIUpCallNode.Arg4 {
 
     @Specialization
     @TruffleBoundary
-    Object handleStrings(String description, String mode, String className, RExternalPtr connAddr) {
-        try {
-            return new NativeRConnection(description, mode, className, connAddr).asVector();
-        } catch (IOException e) {
-            return InvalidConnection.instance.asVector();
-        }
-    }
-
-    protected static Node createAsPointerNode() {
-        return Message.AS_POINTER.createNode();
-    }
-
-    @Specialization
-    @TruffleBoundary
-    Object handleAddresses(TruffleObject description, TruffleObject mode, TruffleObject className, RExternalPtr connAddr,
-                    @Cached("createAsPointerNode()") Node descriptionAsPtrNode, @Cached("createAsPointerNode()") Node modeAsPtrNode, @Cached("createAsPointerNode()") Node classNameAsPtrNode) {
-        try {
-            return handleAddresses(ForeignAccess.sendAsPointer(descriptionAsPtrNode, description), ForeignAccess.sendAsPointer(modeAsPtrNode, mode),
-                            ForeignAccess.sendAsPointer(classNameAsPtrNode, className), connAddr);
-        } catch (UnsupportedMessageException e) {
-            throw RInternalError.shouldNotReachHere(e);
-        }
-    }
-
-    private static Object handleAddresses(long description, long mode, long className, RExternalPtr connAddr) {
+    Object handleStrings(Object description, Object mode, Object className, RExternalPtr connAddr, @Cached("create()") NativeStringCastNode nscn) {
         try {
-            return new NativeRConnection(readNativeString(description), readNativeString(mode), readNativeString(className), connAddr).asVector();
+            return new NativeRConnection(nscn.executeObject(description), nscn.executeObject(mode), nscn.executeObject(className), connAddr).asVector();
         } catch (IOException e) {
             return InvalidConnection.instance.asVector();
         }
     }
-
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/Str2TypeNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/Str2TypeNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbc29c664e479ce754ebd79f06161476eb6e0200
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/Str2TypeNode.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.nodes;
+
+import java.util.HashMap;
+
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
+
+public abstract class Str2TypeNode extends FFIUpCallNode.Arg1 {
+
+    private static HashMap<String, Integer> name2typeTable;
+
+    static {
+        name2typeTable = new HashMap<>(26);
+        name2typeTable.put("NULL", SEXPTYPE.NILSXP.code);
+        /* real types */
+        name2typeTable.put("symbol", SEXPTYPE.SYMSXP.code);
+        name2typeTable.put("pairlist", SEXPTYPE.LISTSXP.code);
+        name2typeTable.put("closure", SEXPTYPE.CLOSXP.code);
+        name2typeTable.put("environment", SEXPTYPE.ENVSXP.code);
+        name2typeTable.put("promise", SEXPTYPE.PROMSXP.code);
+        name2typeTable.put("language", SEXPTYPE.LANGSXP.code);
+        name2typeTable.put("special", SEXPTYPE.SPECIALSXP.code);
+        name2typeTable.put("builtin", SEXPTYPE.BUILTINSXP.code);
+        name2typeTable.put("char", SEXPTYPE.CHARSXP.code);
+        name2typeTable.put("logical", SEXPTYPE.LGLSXP.code);
+        name2typeTable.put("integer", SEXPTYPE.INTSXP.code);
+        name2typeTable.put("double", SEXPTYPE.REALSXP.code);
+        /*-  "real", for R <= 0.61.x */
+        name2typeTable.put("complex", SEXPTYPE.CPLXSXP.code);
+        name2typeTable.put("character", SEXPTYPE.STRSXP.code);
+        name2typeTable.put("...", SEXPTYPE.DOTSXP.code);
+        name2typeTable.put("any", SEXPTYPE.ANYSXP.code);
+        name2typeTable.put("expression", SEXPTYPE.EXPRSXP.code);
+        name2typeTable.put("list", SEXPTYPE.VECSXP.code);
+        name2typeTable.put("externalptr", SEXPTYPE.EXTPTRSXP.code);
+        name2typeTable.put("bytecode", SEXPTYPE.BCODESXP.code);
+        name2typeTable.put("weakref", SEXPTYPE.WEAKREFSXP.code);
+        name2typeTable.put("raw", SEXPTYPE.RAWSXP.code);
+        name2typeTable.put("S4", SEXPTYPE.S4SXP.code);
+        name2typeTable.put("numeric", SEXPTYPE.REALSXP.code);
+        name2typeTable.put("name", SEXPTYPE.SYMSXP.code);
+    }
+
+    @Child private Node clazzIsPtrNode;
+
+    public static Str2TypeNode create() {
+        return Str2TypeNodeGen.create();
+    }
+
+    @Specialization
+    Object handleString(Object n, @Cached("create()") NativeStringCastNode sc) {
+        String name = sc.executeObject(n);
+        if (name == null) {
+            return -1;
+        }
+        Integer result = name2typeTable.get(name);
+        return result != null ? result : -1;
+    }
+
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
index 115713fabac830b3415f1a145e1abde714fb6d5a..e6d51dbe8cf31523fe99b9882a4e1a984b8691ac 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java
@@ -38,6 +38,7 @@ import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RScalarList;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RSequence;
+import com.oracle.truffle.r.runtime.data.RString;
 
 public abstract class FFIWrapNode extends Node {
 
@@ -63,6 +64,11 @@ public abstract class FFIWrapNode extends Node {
         return wrap(RDataFactory.createStringVectorFromScalar(value));
     }
 
+    @Specialization
+    protected static Object wrap(RString value) {
+        return wrap(RDataFactory.createStringVectorFromScalar(value.getValue()));
+    }
+
     @Specialization
     protected static Object wrap(RInteger value) {
         return wrap(RDataFactory.createIntVectorFromScalar(value.getValue()));
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
index 7151f48559114fb8d46b16b17ced7a418ab8e13e..a576084b4f92e967c536c75f70d17c849d4f3745 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
@@ -32,7 +32,9 @@ import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodes.GetAttrib;
 import com.oracle.truffle.r.ffi.impl.nodes.AttributesAccessNodes.TAG;
 import com.oracle.truffle.r.ffi.impl.nodes.CoerceNodes.CoerceVectorNode;
 import com.oracle.truffle.r.ffi.impl.nodes.CoerceNodes.VectorToPairListNode;
+import com.oracle.truffle.r.ffi.impl.nodes.DoMakeClassNode;
 import com.oracle.truffle.r.ffi.impl.nodes.DuplicateNodes;
+import com.oracle.truffle.r.ffi.impl.nodes.GetClassDefNode;
 import com.oracle.truffle.r.ffi.impl.nodes.EnvNodes.LockBindingNode;
 import com.oracle.truffle.r.ffi.impl.nodes.EnvNodes.UnlockBindingNode;
 import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CAARNode;
@@ -57,6 +59,7 @@ import com.oracle.truffle.r.ffi.impl.nodes.NewCustomConnectionNode;
 import com.oracle.truffle.r.ffi.impl.nodes.RMakeExternalPtrNode;
 import com.oracle.truffle.r.ffi.impl.nodes.RandFunctionsNodes;
 import com.oracle.truffle.r.ffi.impl.nodes.RfEvalNode;
+import com.oracle.truffle.r.ffi.impl.nodes.Str2TypeNode;
 import com.oracle.truffle.r.ffi.impl.nodes.TryRfEvalNode;
 import com.oracle.truffle.r.ffi.processor.RFFICpointer;
 import com.oracle.truffle.r.ffi.processor.RFFICstring;
@@ -111,9 +114,11 @@ public interface StdUpCallsRFFI {
 
     void Rf_defineVar(Object symbolArg, Object value, Object envArg);
 
-    Object R_getClassDef(@RFFICstring String clazz);
+    @RFFIUpCallNode(GetClassDefNode.class)
+    Object R_getClassDef(@RFFICstring(convert = false) Object clazz);
 
-    Object R_do_MAKE_CLASS(@RFFICstring String clazz);
+    @RFFIUpCallNode(DoMakeClassNode.class)
+    Object R_do_MAKE_CLASS(@RFFICstring(convert = false) Object clazz);
 
     @RFFIUpCallNode(MiscNodes.RDoNewObjectNode.class)
     Object R_do_new_object(Object classDef);
@@ -403,7 +408,8 @@ public interface StdUpCallsRFFI {
 
     Object R_MethodsNamespace();
 
-    int Rf_str2type(@RFFICstring String name);
+    @RFFIUpCallNode(Str2TypeNode.class)
+    int Rf_str2type(@RFFICstring(convert = false) Object name);
 
     int FASTR_getConnectionChar(Object obj);
 
diff --git a/com.oracle.truffle.r.native/Makefile b/com.oracle.truffle.r.native/Makefile
index 514fd0857f73d08e6155749f40f68344b75049ce..159c2720d3a39a7032180944bd783e3d5d77db06 100644
--- a/com.oracle.truffle.r.native/Makefile
+++ b/com.oracle.truffle.r.native/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2018, 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
@@ -21,7 +21,7 @@
 # questions.
 #
 
-.PHONY: all clean 
+.PHONY: all clean
 
 export TOPDIR = $(CURDIR)
 export FASTR_R_HOME=$(abspath $(TOPDIR)/..)
@@ -30,6 +30,15 @@ export FASTR_NATIVE_DIR = $(TOPDIR)
 export R_VERSION = 3.4.0
 export GNUR_HOME = $(TOPDIR)/gnur/patch-build
 
+ifeq ($(FASTR_RFFI),llvm)
+ifndef FASTR_LLVM_TOOLS
+ifdef FASTR_LLVM_FOR_DRAGONEGG_HOME
+export FASTR_LLVM_TOOLS = $(FASTR_LLVM_FOR_DRAGONEGG_HOME)/bin
+$(info FASTR_LLVM_TOOLS set to $(FASTR_LLVM_TOOLS))
+endif
+endif
+endif
+
 $(info R_VERSION: $(R_VERSION))
 $(info GNUR_HOME: $(GNUR_HOME))
 
@@ -43,7 +52,7 @@ $(info GNUR_HOME_BINARY not set. Assuming the default location at $(GNUR_HOME_BI
 endif
 
 # Completely accurate dependency analysis is very difficult for this project, so use a version number
-# to force a clean build, and elsewhere use sentinels to avoid rebuilding when we can't compute the 
+# to force a clean build, and elsewhere use sentinels to avoid rebuilding when we can't compute the
 # dependencies accurately.
 
 all: checkversion
@@ -54,7 +63,7 @@ all: checkversion
 	$(MAKE) -C run
 	cp version.source version.built
 
-clean: 
+clean:
 	$(MAKE) -C include clean
 	$(MAKE) -C fficall clean
 	$(MAKE) -C run clean
diff --git a/com.oracle.truffle.r.native/fficall/Makefile b/com.oracle.truffle.r.native/fficall/Makefile
index f6176fd2d0aa5d3f78ee729487b1dfa2c7a38ecf..e6e0b6a202f5e7ebfec8c341944fe6501e0b5d8d 100644
--- a/com.oracle.truffle.r.native/fficall/Makefile
+++ b/com.oracle.truffle.r.native/fficall/Makefile
@@ -57,7 +57,7 @@ ifeq ($(FASTR_RFFI),managed)
 else
 ifeq ($(OS_NAME),Darwin)
 	$(DYLIB_LD) $(DYLIB_LDFLAGS) -Wl,-rpath,@loader_path/ -o $(R_LIB) $(wildcard lib/*.o) -L$(FASTR_LIB_DIR) -ldl -lRblas -lRlapack  -lpcre -lz $(VERSION_FLAGS)
-ifneq ($(FASTR_RFFI),llvm)	
+ifneq ($(FASTR_RFFI),llvm)
 	install_name_tool -change libRblas.dylib @rpath/libRblas.dylib $(R_LIB)
 	install_name_tool -change libRlapack.dylib @rpath/libRlapack.dylib $(R_LIB)
 	install_name_tool -id @rpath/libR.dylib $(R_LIB)
@@ -80,6 +80,7 @@ fficall.done: common.done
 
 else
 ifeq ($(FASTR_RFFI),llvm)
+export R_PACKAGE_DIR="lib"
 fficall.done: common.done
 	$(MAKE) -C src/truffle_llvm all
 	touch fficall.done
@@ -90,7 +91,7 @@ endif #nfi
 endif #managed
 
 common.done:
-	$(MAKE) -C src/common all	
+	$(MAKE) -C src/common all
 	touch common.done
 
 clean:
@@ -109,4 +110,3 @@ endif
 	rm -rf $(R_LIB)
 	rm -rf fficall.done
 	rm -rf common.done
-
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
index 307b1d2fcd52091e8055fa8d94262cfc8684ea77..1a6bc2c49b7a21559098ea7126a3d1a70ec9c902 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
@@ -288,9 +288,7 @@ typedef Rboolean (*call_Rf_NonNullStringMatch)(SEXP s, SEXP t);
 typedef SEXP (*call_getvar)();
 typedef SEXP (*call_R_ParseVector)(SEXP text, int n, SEXP srcFile);
 typedef SEXPTYPE (*call_Rf_str2type)(const char *s);
-typedef SEXP (*call_CLOENV)(SEXP closure);
 typedef SEXP (*call_octsize)(SEXP size);
-typedef void (*call_Rf_PrintValue)(SEXP x);
 
 // connections
 
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c
index 1f8079ac7515c46a009fe93d244ab87af3d2020d..734c99bdd75b19f40c5ac23027972176eedcb324 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2015, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -19,22 +19,25 @@
 // The table of transient objects that have been allocated dur the current FFI call
 static void **tMemTable;
 // hwm of tMemTable
-static int tMemTableIndex;
+static int tMemTableIndex = -1;
 static int tMemTableLength;
 
 void *R_chk_calloc(size_t nelem, size_t elsize);
 
 // Memory that is auto-reclaimed across FFI calls
 char *R_alloc(size_t n, int size) {
+	tMemTableIndex++;
     void *p = R_chk_calloc(n, size);
     if (tMemTableIndex >= tMemTableLength) {
-	int newLength = 2 * tMemTableLength;
+	int newLength = tMemTableLength == 0 ? 1 : 2 * tMemTableLength;
 	void *newtMemTable = malloc(sizeof(void*) * newLength);
 	if (newtMemTable == NULL) {
 	    fatalError("malloc failure");
 	}
-	memcpy(newtMemTable, tMemTable, tMemTableLength * sizeof(void*));
-	free(tMemTable);
+	if (tMemTableLength > 0) {
+		memcpy(newtMemTable, tMemTable, tMemTableLength * sizeof(void*));
+		free(tMemTable);
+	}
 	tMemTable = newtMemTable;
 	tMemTableLength = newLength;
     }
@@ -54,9 +57,10 @@ char* S_realloc(char *p, long a, long b, int size) {
 
 void allocExit() {
     int i;
-    for (i = 0; i < tMemTableIndex; i++) {
+    for (i = 0; i <= tMemTableIndex; i++) {
 	free(tMemTable[i]);
     }
+    tMemTableIndex = 0;
 }
 
 void *R_chk_calloc(size_t nelem, size_t elsize) {
@@ -116,4 +120,3 @@ SEXP Rf_allocS4Object() {
 	unimplemented("Rf_allocS4Object unimplemented");
 	return NULL;
 }
-
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile b/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile
index 7c53c00be0dd72304ec050614f070433a4c29214..6861f1ebc71f116b02a5461391cfce1a6ad9fbfd 100644
--- a/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2018, 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
@@ -25,6 +25,7 @@
 
 SUBDIRS = base compiler datasets utils grDevices graphics grid parallel splines stats stats4 methods tools
 export FASTR_LIBRARY_DIR = $(abspath $(TOPDIR)/../library)
+export R_PACKAGE_DIR="."
 
 all: libdir make_subdirs
 
@@ -39,6 +40,6 @@ clean_subdirs:
 	for dir in $(SUBDIRS); do \
 		$(MAKE) PACKAGE=$$dir -C $$dir clean || exit 1; \
 	done
-	
+
 libdir:
 	mkdir -p $(FASTR_LIBRARY_DIR)
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile
index 20981356dc097eca04fb87403d78872f5ff8c180..ed0b9d2ac4dced1d261355f019cbb3d9b048894a 100644
--- a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2018, 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
@@ -33,5 +33,4 @@ endif
 
 PKG_LIBS := $(LAPACK_LIBS) $(BLAS_LIBS) -L$(FASTR_LIB_DIR) $(FLIBS)
 PKG_INCLUDES = -I src
-
 include ../lib.mk
diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-ar b/com.oracle.truffle.r.native/llvm_tools/llvm-ar
index 2462ea65edb0de5e818c42ebd2f05d7cb4263696..2045a4ef823ca58a12b1c07b6892882f551b0739 100755
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-ar
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-ar
@@ -25,13 +25,6 @@
 SOURCE="$0"
 DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
 
-while [[ $# -gt 0 ]]
-do
-	f=`basename $1`
-	ext=${f##*.}
-	if [ $ext == 'o' ]
-	then
-		echo $1 >> $R_PACKAGE_DIR/libobjects
-	fi
-	shift
-done
+. $DIR/llvm-helper
+
+create_bc_archive $@
diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-c++ b/com.oracle.truffle.r.native/llvm_tools/llvm-c++
index ee6af85450f4d49ce68115f66c972da8fd3e8db7..ec93f97e3d15ef4168b0221b2e714401f2ef4b28 100755
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-c++
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-c++
@@ -31,12 +31,23 @@ analyze_args "$@"
 
 if [ $is_link -eq 1 ]
 then
-  extraObj=`cat $R_PACKAGE_DIR/libobjects`
+  extraObj=""
+  if [ -f "$R_PACKAGE_DIR/libobjects" ]; then
+     extraObj=`cat "$R_PACKAGE_DIR/libobjects"`
+  fi
   create_bc_lib $@ $extraObj
 else
   llvm_tool=clang++
   get_llvm_tool
+  unamestr=`uname`
+  if [[ "$unamestr" == 'Linux' ]]; then
+    llvm_args="-stdlib=libc++ -I/usr/include/libcxxabi $llvm_args"
+  fi
   runit $llvm_tool_bin $llvm_args
-  mem2reg_opt
-  fake_obj
+
+  # the llvm_ir_file is empty if the result is sent to stdout
+  if [ -n "$llvm_ir_file" ]; then
+    mem2reg_opt
+    fake_obj
+  fi
 fi
diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-cc b/com.oracle.truffle.r.native/llvm_tools/llvm-cc
index 1d88276ba548d5963757f5e6d168930e76822097..42acf7a3271e7f3dc4c266c76d8928ce8940ae91 100755
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-cc
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-cc
@@ -29,15 +29,20 @@ DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
 fortran=0
 analyze_args "$@"
 
-
 if [ $is_link -eq 1 ]
 then
-  extraObj=`cat $R_PACKAGE_DIR/libobjects`
+  extraObj=""
+  if [ -f "$R_PACKAGE_DIR/libobjects" ]; then
+     extraObj=`cat "$R_PACKAGE_DIR/libobjects"`
+  fi
   create_bc_lib $@ $extraObj
 else
   llvm_tool=clang
   get_llvm_tool
   runit $llvm_tool_bin $llvm_args
-  mem2reg_opt
-  fake_obj
+  # the llvm_ir_file is empty if the result is sent to stdout
+  if [ -n "$llvm_ir_file" ]; then
+    mem2reg_opt
+    fake_obj
+  fi
 fi
diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-fc b/com.oracle.truffle.r.native/llvm_tools/llvm-fc
index 084f68d2df945ab446df70d3df1a56f090f34770..03bd793753a3789d904cdb23a54af2d4c1d759e6 100755
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-fc
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-fc
@@ -59,5 +59,8 @@ ll_to_bc
 runit $FASTR_LLVM_GFORTRAN_LLVM_AS $llvm_ir_file -o $llvm_ir_bc_file
 runit rm $llvm_ir_file
 llvm_ir_file=$llvm_ir_bc_file
-mem2reg_opt
-fake_obj
+# the llvm_ir_file is empty if the result is sent to stdout
+if [ -n "$llvm_ir_file" ]; then
+  mem2reg_opt
+  fake_obj
+fi
diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-helper b/com.oracle.truffle.r.native/llvm_tools/llvm-helper
index 598bb39e4058d6469a6d9d94fb69e5e0af4cb252..2f06ecefc74eeeb388e7254d19e9f884609e2195 100644
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-helper
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-helper
@@ -62,26 +62,26 @@ function analyze_args() {
 
   is_link=0
   llvm_ir_file=""
-  
+
   while [[ $# -gt 0 ]]
   do
     llvm_args+="$1 "
     case $1 in
       -o)
         shift
-	p=$1
-	f=`basename $p`
-	d=`dirname $p`
-	ext=${f##*.}
-	if [ $ext == 'so' ] || [ $ext == 'dylib' ]
-	then
-	  is_link=1
-	elif [ $ext == 'o' ]
-	then
-	  llvm_ir_file=${d}/${f%%.*}
-	  llvm_ir_file+=$llvm_file_ext
-	  llvm_args+="$llvm_ir_file "
-	fi
+		p=$1
+		f=`basename $p`
+		d=`dirname $p`
+		ext=${f##*.}
+		if [ $ext == 'so' ] || [ $ext == 'dylib' ]
+		then
+		  is_link=1
+		elif [ $ext == 'o' ]
+		then
+		  llvm_ir_file=${d}/${f%%.*}
+		  llvm_ir_file+=$llvm_file_ext
+		  llvm_args+="$llvm_ir_file "
+		fi
       ;;
      *)
      ;;
@@ -96,9 +96,9 @@ function analyze_args() {
 # path to tool (defaults to plain ${llvm_tool}, assumed to be on the PATH)
 
 function get_llvm_tool() {
-  if [ -n "${FASTR_LLVM_HOME}" ]
+  if [ -n "${FASTR_LLVM_TOOLS}" ]
   then
-    llvm_tool_bin=${FASTR_LLVM_HOME}/${llvm_tool}
+    llvm_tool_bin=${FASTR_LLVM_TOOLS}/${llvm_tool}
   else
     llvm_tool_uc=`echo ${llvm_tool} | tr /a-z/ /A-Z/ | tr /+/ /P/`
     x=FASTR_LLVM_${llvm_tool_uc}
@@ -111,7 +111,6 @@ function get_llvm_tool() {
   fi
 }
 
-
 function mem2reg_opt() {
    llvm_tool="opt"
    get_llvm_tool
@@ -126,40 +125,118 @@ function mem2reg_opt() {
 function fake_obj() {
   f=`basename $llvm_ir_file`
   d=`dirname $llvm_ir_file`
-  runit touch ${d}/${f%%.*}.o 
+  runit touch ${d}/${f%%.*}.o
 }
 
 # Input: all the arguments to the original command line
 function create_bc_lib() {
   bcfiles=""
   lib=""
+  statlibs="$R_PACKAGE_DIR/statlibs"
+  linkedLibs="LIBS"
+  > $linkedLibs
   while [[ $# -gt 0 ]]
   do
     case $1 in
       -o)
         shift
-	lib=$1
-      ;;
+		    lib=$1
+        ;;
+      -l*)
+		    linkedLib=`echo $1 | cut -c 3-`
+        statLibFound='0'
+        if [ -f "$statlibs" ]; then
+          statLibFound=`cat "$statlibs" | grep "lib${linkedLib}.a" | wc -l`
+        fi
+        if [ $statLibFound == '0' ]
+		    then
+          echo $linkedLib >> $linkedLibs
+		    fi
+        ;;
+      -*)
+        # ignore other options
+        ;;
+      *)
+        f=$(basename $1)
+     	  ext=${f##*.}
+		    if [ $ext == 'o' ]
+		    then
+	  		   fn="$(dirname $1)/${f%%.*}.bc"
+			     bcfiles+="$fn "
+		    fi
+        ;;
+    esac
+    shift
+  done
+
+# we do not have the luxury of controlling the name of the entry (unlike in python)
+# it will be the pathname, which we will reduce to a module name on input in FastR
+
+# link the bitcode files into a single one using llvm-link before zipping it
+  llvm_tool=llvm-link
+  get_llvm_tool
+  echo "Linking $lib.bc from LLVM modules: $bcfiles"
+  runit $llvm_tool_bin $bcfiles -o $lib.bc
+  runit zip -r $lib $lib.bc $linkedLibs
+  rm $lib.bc
+}
+
+# It appends objects constituting a static library to the list of extra object files.
+# This list is maintained in $R_PACKAGE_DIR/libobjects and is later read in llvm-cc and
+# llvm-c++ to append the object files from the list to other objects when making
+# the package dynamic library. This mechanism is a workaround for the fact that the llvm
+# linker does not support linking to static libraries, as the standard linker does
+# through the -l and -L options.
+function create_bc_archive() {
+
+  # Create a CSV file containing all object files constituting the archive (i.e. the static library).
+  # The CSV has two columns: the object name in the archive and the full path of the object file.
+  # The object name columns serves as the join column when joining with the set of unique
+  # symbols objects (see below) to get the final list of objects to be linked with
+  # the package dynamic library in the end.
+  shift
+  archname=$1
+  arargs="rcs $archname "
+  shift
+
+  archObjCSVtmp="archived_objects.tmp"
+  archObjCSV="archived_objects.csv"
+  exportedObjCSV="exported_objects.csv"
+  > $archObjCSV
+
+  while [[ $# -gt 0 ]]
+  do
+    case $1 in
      *)
         f=$1
      	ext=${f##*.}
 	if [ $ext == 'o' ]
 	then
+	  fullPath=`echo $(cd $(dirname $1) && pwd -P)/$(basename $1)`
 	  fn=${f%%.*}.bc
-	  bcfiles+="$fn "
+	  arargs+="$fn "
+	  echo "$(basename $fn) $fullPath" >> $archObjCSVtmp
+	else
+	  arargs+="$1 "
 	fi
      ;;
     esac
     shift
   done
 
-# we do not have the luxury of controlling the name of the entry (unlike in python)
-# it will be the pathname, which we will reduce to a module name on input in FastR
+  sort -d --field-separator=' ' --key=1 $archObjCSVtmp > $archObjCSV
 
-# link the bitcode files into a single one using llvm-link before zipping it
-  llvm_tool=llvm-link
-  get_llvm_tool
-  runit $llvm_tool_bin $bcfiles -o $lib.bc
-  runit zip -r $lib $lib.bc
-  rm $lib.bc
+  # Create the archive (via llvm-ar) that is then used to read the symbol table via llvm-nm.
+  # The symbol table allows for selecting a set of objects exporting unique symbols.
+  llvm-ar $arargs
+
+  # This command extracts a set of objects from the archive that do not export duplicate symbols
+  llvm-nm -print-file-name $archname | grep "\-\-\-\-" | awk -F ' ' '{print $1" "$4}' | sort -d --field-separator=' ' --key=2 -u | awk -F ':' '{print $2}' | sort -d -u > $exportedObjCSV
+
+  # Join the archived objects CSV with the unique symbols objects CSV to get the list of objects to be statically linked to the package dynamic library.
+  # Append the result to the global list of extra object files.
+  join -t " " -1 1 -2 1 $archObjCSV $exportedObjCSV | awk -F ' ' '{print $2}' >> "$R_PACKAGE_DIR/libobjects"
+
+  # Record the archive (static library) name to distinguish between LLVM static libs and native libs when linking (via -l)
+  echo $archname >> "$R_PACKAGE_DIR/statlibs"
 }
diff --git a/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm b/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm
index d9a5864d77d6d0115a2d5ab58a250f6e39a18487..c4972785f1b97ace17efcf41e7d9d36f203e2910 100644
--- a/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm
+++ b/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm
@@ -8,6 +8,11 @@ d
 i
 CXX = $(R_HOME)/bin/llvm-c++
 .
+/^CXX11 =/
+d
+i
+CXX11 = $(R_HOME)/bin/llvm-c++
+.
 /^FC =/
 d
 i
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java
index 1f7f724a112834a8b6167f6033fd92acd594c93b..cf4b856b0a456b684d605d25c2fb3a05fdcec023 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapper.java
@@ -41,7 +41,6 @@ import com.oracle.truffle.r.runtime.RRuntime;
  */
 public final class CharSXPWrapper extends RObject implements RTruffleObject {
     private static final CharSXPWrapper NA = new CharSXPWrapper(RRuntime.STRING_NA);
-
     private String contents;
     private byte[] bytes;
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
index 970c53a91db9977ee5094312eddea7c689293683..09b82c05c43a5a1e6f9dbf57cceae1b0c579f59b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
@@ -114,6 +114,16 @@ public final class NativeDataAccess {
          */
         private long length;
 
+        /**
+         * It maintains the <code>1-?</code> relationship between this object and its native wrapper
+         * through which the native code accesses it. For instance, Sulong implements the "pointer"
+         * equality of two objects that are not pointers (i.e. <code>IS_POINTER</code> returns
+         * <code>false</code>) as the reference equality of the objects. It follows that the pointer
+         * comparison would fail if the same <code>RObject</code> instance were wrapped by two
+         * different native wrappers.
+         */
+        private Object nativeWrapper;
+
         NativeMirror() {
             this.id = counter.incrementAndGet();
         }
@@ -204,8 +214,8 @@ public final class NativeDataAccess {
         if (arg instanceof RObject) {
             RObject obj = (RObject) arg;
             NativeMirror mirror = (NativeMirror) obj.getNativeMirror();
-            if (mirror == null) {
-                mirror = putMirrorObject(arg, obj);
+            if (mirror == null || mirror.id == 0) {
+                mirror = putMirrorObject(arg, obj, mirror);
             }
             return mirror.id;
         }
@@ -213,16 +223,19 @@ public final class NativeDataAccess {
     }
 
     @TruffleBoundary
-    private static NativeMirror putMirrorObject(Object arg, RObject obj) {
-        NativeMirror mirror;
-        obj.setNativeMirror(mirror = arg instanceof CustomNativeMirror ? new NativeMirror(((CustomNativeMirror) arg).getCustomMirrorAddress()) : new NativeMirror());
+    private static NativeMirror putMirrorObject(Object arg, RObject obj, NativeMirror oldMirror) {
+        NativeMirror newMirror;
+        obj.setNativeMirror(newMirror = arg instanceof CustomNativeMirror ? new NativeMirror(((CustomNativeMirror) arg).getCustomMirrorAddress()) : new NativeMirror());
+        if (oldMirror != null) {
+            newMirror.nativeWrapper = oldMirror.nativeWrapper;
+        }
         // System.out.println(String.format("adding %16x = %s", mirror.id,
         // obj.getClass().getSimpleName()));
-        nativeMirrors.put(mirror.id, new WeakReference<>(obj));
+        nativeMirrors.put(newMirror.id, new WeakReference<>(obj));
         if (TRACE_MIRROR_ALLOCATION_SITES) {
-            registerAllocationSite(arg, mirror);
+            registerAllocationSite(arg, newMirror);
         }
-        return mirror;
+        return newMirror;
     }
 
     @TruffleBoundary
@@ -662,6 +675,7 @@ public final class NativeDataAccess {
         return mirror.dataAddress;
     }
 
+    @TruffleBoundary
     public static String readNativeString(long addr) {
         int len;
         for (len = 0; UnsafeAdapter.UNSAFE.getByte(addr + len) != 0; len++) {
@@ -691,4 +705,23 @@ public final class NativeDataAccess {
         mirror.length = length;
 
     }
+
+    public static void setNativeWrapper(RObject obj, Object wrapper) {
+        NativeMirror mirror = (NativeMirror) obj.getNativeMirror();
+        if (mirror == null) {
+            mirror = new NativeMirror(0);
+            obj.setNativeMirror(mirror);
+        }
+        mirror.nativeWrapper = wrapper;
+    }
+
+    public static Object getNativeWrapper(RObject obj) {
+        NativeMirror mirror = (NativeMirror) obj.getNativeMirror();
+        if (mirror == null) {
+            return null;
+        } else {
+            return mirror.nativeWrapper;
+        }
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java
index 1b3555e35bade73c1fea251848d3169a5205df5d..d80f67f4bfb92aa100155117965e7870442e499f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, 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
@@ -33,4 +33,5 @@ public abstract class RObject {
     public final Object getNativeMirror() {
         return nativeMirror;
     }
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
index e3be9c96ea3e37a40fd7df240ff2bfbe95fa3640..8ba6f70a6a9a78a99fd0fcf5609becef434cf1af 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
@@ -390,6 +390,9 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra
 
             @Override
             public RPairList next() {
+                if (plt instanceof RLanguage) {
+                    plt = ((RLanguage) plt).getPairList();
+                }
                 assert plt instanceof RPairList;
                 RPairList curr = (RPairList) plt;
                 plt = curr.cdr;
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
index 1782f4b2ef57276d7ccc638f17c53ac1acb80cd1..e37ea7538097fd365f84645c4c9845dbbe46919e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
@@ -134,7 +134,7 @@ public final class FastRSession implements RSession {
         ChildContextInfo ctx = ChildContextInfo.create(params, env, contextKind, contextKind == ContextKind.SHARE_NOTHING ? null : mainRContext, input, output, output);
         RContext.childInfo = ctx;
 
-        return Context.newBuilder("R").engine(mainEngine).build();
+        return Context.newBuilder("R", "llvm").engine(mainEngine).build();
     }
 
     private FastRSession() {
@@ -154,7 +154,7 @@ public final class FastRSession implements RSession {
             ChildContextInfo info = ChildContextInfo.create(params, null, ContextKind.SHARE_NOTHING, null, input, output, output);
             RContext.childInfo = info;
             mainEngine = Engine.newBuilder().in(input).out(output).err(output).build();
-            mainContext = Context.newBuilder("R").engine(mainEngine).build();
+            mainContext = Context.newBuilder("R", "llvm").engine(mainEngine).build();
             mainRContext = mainContext.eval(GET_CONTEXT).asHostObject();
         } finally {
             try {
diff --git a/documentation/dev/truffle_llvm_ffi.md b/documentation/dev/truffle_llvm_ffi.md
index c0cbb908c0ec77477037ff3386533ea9fb05fa80..bff8c9114a7b862b5262873317c8832898a08391 100644
--- a/documentation/dev/truffle_llvm_ffi.md
+++ b/documentation/dev/truffle_llvm_ffi.md
@@ -65,7 +65,7 @@ FastR necessarily provides very fine control over the versions of the llvm tools
 
 The tools needed to build FastR and to install packages containing native code are `clang`, `clang++` and `opt`. Precisely which versions of these tools are used can be controlled in two ways.
 
-1. Set `FASTR_LLVM_HOME` to a directory containing the tools, named as above. N.B. Since MacPorts uses names of the form `clang-mp-3.8` this requires using symbolic links. E.g. create a directory called, say, `llvm-3.8` and symlink to the MacPorts binary, e.g., `clang-mp-3.8` and name it as `clang`. Then set `FASTR_LLVM_HOME` to that directory.
+1. Set `FASTR_LLVM_TOOLS` to a directory containing the tools, named as above. N.B. Since MacPorts uses names of the form `clang-mp-3.8` this requires using symbolic links. E.g. create a directory called, say, `llvm-3.8` and symlink to the MacPorts binary, e.g., `clang-mp-3.8` and name it as `clang`. Then set `FASTR_LLVM_TOOLS` to that directory.
 2. Set `FASTR_LLVM_CLANG`, `FASTR_LLVM_CLANGPP` and `FASTR_LLVM_OPT` to the actual binary images, e.g., `export FASTR_LLVM_CLANG=/opt/local/bin/clang-mp-3.8`.
 
 Not all versions of the llvm tools can compile FastR. `clang-3.2` that is downloaded as part of the DragonEgg build is known to work. This currently is placed in `sulong/cache/tools/llvm/bin` by the DragonEgg build and, again, can be copied to a shared location. `clang-3.8` and `clang-4.0` are known not to work, but `clang-3.9` does.