From 86bcea6011406de21c5c4a6a38bfd4c4ecf71fb8 Mon Sep 17 00:00:00 2001
From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com>
Date: Thu, 22 Feb 2018 20:32:35 +0100
Subject: [PATCH] Miscellaneous LLVM-related fixes

---
 .../ffi/impl/common/JavaUpCallsRFFIImpl.java  | 233 ++++++++----------
 .../r/ffi/impl/llvm/TruffleLLVM_Call.java     |  17 +-
 .../r/ffi/impl/llvm/TruffleLLVM_Context.java  |   4 +
 .../upcalls/BytesToNativeCharArrayCallMR.java |   1 +
 .../r/ffi/impl/nodes/DoMakeClassNode.java     |  47 ++++
 .../r/ffi/impl/nodes/GetClassDefNode.java     |  47 ++++
 .../ffi/impl/nodes/NativeStringCastNode.java  |  66 +++++
 .../impl/nodes/NewCustomConnectionNode.java   |  37 +--
 .../r/ffi/impl/nodes/Str2TypeNode.java        |  84 +++++++
 .../r/ffi/impl/upcalls/StdUpCallsRFFI.java    |  12 +-
 .../fficall/src/truffle_llvm/Memory.c         |  14 +-
 .../llvm_tools/llvm-ar                        |  13 +-
 .../llvm_tools/llvm-c++                       |  20 +-
 .../llvm_tools/llvm-cc                        |  20 +-
 .../llvm_tools/llvm-fc                        |   7 +-
 .../llvm_tools/llvm-helper                    | 115 +++++++--
 .../r/runtime/data/CharSXPWrapper.java        |   1 -
 .../r/runtime/data/NativeDataAccess.java      |   1 +
 .../truffle/r/runtime/data/RObject.java       |  19 +-
 .../truffle/r/test/generate/FastRSession.java |   4 +-
 20 files changed, 536 insertions(+), 226 deletions(-)
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/DoMakeClassNode.java
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/GetClassDefNode.java
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java
 create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/Str2TypeNode.java

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 c7984a2e49..b219056de0 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
@@ -1869,100 +1826,101 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
                 }
             });
         }
-    }
 
-    @MessageResolution(receiverType = VectorWrapper.class)
-    public static class VectorWrapperMR {
+        @MessageResolution(receiverType = VectorWrapper.class)
+        public static class VectorWrapperMR {
 
-        @Resolve(message = "IS_POINTER")
-        public abstract static class IntVectorWrapperNativeIsPointerNode extends Node {
-            protected Object access(@SuppressWarnings("unused") VectorWrapper receiver) {
-                return false;
+            @Resolve(message = "IS_POINTER")
+            public abstract static class IntVectorWrapperNativeIsPointerNode extends Node {
+                protected Object access(@SuppressWarnings("unused") VectorWrapper receiver) {
+                    return false;
+                }
             }
-        }
 
-        @Resolve(message = "TO_NATIVE")
-        public abstract static class IntVectorWrapperNativeAsPointerNode extends Node {
-            protected Object access(VectorWrapper receiver) {
-                return new VectorWrapperNativePointer(receiver.vector);
+            @Resolve(message = "TO_NATIVE")
+            public abstract static class IntVectorWrapperNativeAsPointerNode extends Node {
+                protected Object access(VectorWrapper receiver) {
+                    return new VectorWrapperNativePointer(receiver.vector);
+                }
             }
-        }
 
-        @Resolve(message = "HAS_SIZE")
-        public abstract static class VectorWrapperHasSizeNode extends Node {
-            protected Object access(@SuppressWarnings("unused") VectorWrapper receiver) {
-                return true;
+            @Resolve(message = "HAS_SIZE")
+            public abstract static class VectorWrapperHasSizeNode extends Node {
+                protected Object access(@SuppressWarnings("unused") VectorWrapper receiver) {
+                    return true;
+                }
             }
-        }
 
-        @Resolve(message = "GET_SIZE")
-        public abstract static class VectorWrapperGetSizeNode extends Node {
-            @Child private Node getSizeMsg = Message.GET_SIZE.createNode();
+            @Resolve(message = "GET_SIZE")
+            public abstract static class VectorWrapperGetSizeNode extends Node {
+                @Child private Node getSizeMsg = Message.GET_SIZE.createNode();
 
-            protected Object access(VectorWrapper receiver) {
-                try {
-                    return ForeignAccess.sendGetSize(getSizeMsg, receiver.vector);
-                } catch (UnsupportedMessageException e) {
-                    throw RInternalError.shouldNotReachHere(e);
+                protected Object access(VectorWrapper receiver) {
+                    try {
+                        return ForeignAccess.sendGetSize(getSizeMsg, receiver.vector);
+                    } catch (UnsupportedMessageException e) {
+                        throw RInternalError.shouldNotReachHere(e);
+                    }
                 }
             }
-        }
 
-        @Resolve(message = "READ")
-        abstract static class VectorWrapperReadNode extends Node {
-            @Child private Node readMsg = Message.READ.createNode();
+            @Resolve(message = "READ")
+            abstract static class VectorWrapperReadNode extends Node {
+                @Child private Node readMsg = Message.READ.createNode();
 
-            public Object access(VectorWrapper receiver, Object index) {
-                try {
-                    return ForeignAccess.sendRead(readMsg, receiver.vector, index);
-                } catch (UnsupportedMessageException | UnknownIdentifierException e) {
-                    throw RInternalError.shouldNotReachHere(e);
+                public Object access(VectorWrapper receiver, Object index) {
+                    try {
+                        return ForeignAccess.sendRead(readMsg, receiver.vector, index);
+                    } catch (UnsupportedMessageException | UnknownIdentifierException e) {
+                        throw RInternalError.shouldNotReachHere(e);
+                    }
                 }
             }
-        }
 
-        @Resolve(message = "WRITE")
-        abstract static class VectorWrapperWriteNode extends Node {
-            @Child private Node writeMsg = Message.WRITE.createNode();
+            @Resolve(message = "WRITE")
+            abstract static class VectorWrapperWriteNode extends Node {
+                @Child private Node writeMsg = Message.WRITE.createNode();
 
-            public Object access(VectorWrapper receiver, Object index, Object value) {
-                try {
-                    return ForeignAccess.sendWrite(writeMsg, receiver.vector, index, value);
-                } catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException e) {
-                    throw RInternalError.shouldNotReachHere(e);
+                public Object access(VectorWrapper receiver, Object index, Object value) {
+                    try {
+                        return ForeignAccess.sendWrite(writeMsg, receiver.vector, index, value);
+                    } catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException e) {
+                        throw RInternalError.shouldNotReachHere(e);
+                    }
                 }
             }
-        }
 
-        @Resolve(message = "IS_EXECUTABLE")
-        abstract static class VectorWrapperIsExecutableNode extends Node {
-            @Child private Node isExecMsg = Message.IS_EXECUTABLE.createNode();
+            @Resolve(message = "IS_EXECUTABLE")
+            abstract static class VectorWrapperIsExecutableNode extends Node {
+                @Child private Node isExecMsg = Message.IS_EXECUTABLE.createNode();
 
-            public Object access(VectorWrapper receiver) {
-                return ForeignAccess.sendIsExecutable(isExecMsg, receiver.vector);
+                public Object access(VectorWrapper receiver) {
+                    return ForeignAccess.sendIsExecutable(isExecMsg, receiver.vector);
+                }
             }
-        }
-
-        @Resolve(message = "EXECUTE")
-        abstract static class VectorWrapperExecuteNode extends Node {
-            @Child private Node execMsg = Message.createExecute(0).createNode();
 
-            protected Object access(VectorWrapper receiver, Object[] arguments) {
-                try {
-                    // 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);
-                } catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) {
-                    throw RInternalError.shouldNotReachHere(e);
+            @Resolve(message = "EXECUTE")
+            abstract static class VectorWrapperExecuteNode extends Node {
+                @Child private Node execMsg = Message.createExecute(0).createNode();
+
+                protected Object access(VectorWrapper receiver, Object[] arguments) {
+                    try {
+                        // 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);
+                    } catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) {
+                        throw RInternalError.shouldNotReachHere(e);
+                    }
                 }
             }
-        }
 
-        @CanResolve
-        public abstract static class VectorWrapperCheck extends Node {
-            protected static boolean test(TruffleObject receiver) {
-                return receiver instanceof VectorWrapper;
+            @CanResolve
+            public abstract static class VectorWrapperCheck extends Node {
+                protected static boolean test(TruffleObject receiver) {
+                    return receiver instanceof VectorWrapper;
+                }
             }
         }
     }
@@ -1973,6 +1931,20 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
         public VectorWrapper(TruffleObject vector) {
             this.vector = vector;
+            ((RObject) vector).setNativeWrapper(this);
+        }
+
+        static Object get(TruffleObject x) {
+            assert x instanceof RObject;
+            Object wrapper = ((RObject) x).getNativeWrapper();
+            if (wrapper != null) {
+                return wrapper;
+            } else {
+                wrapper = new VectorWrapper(x);
+                // Establish the 1-1 relationship between the object and its native wrapper
+                ((RObject) x).setNativeWrapper(wrapper);
+                return wrapper;
+            }
         }
 
         public TruffleObject getVector() {
@@ -1983,38 +1955,49 @@ 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));
+        TruffleObject xto = guaranteeVectorOrNull(x, CharSXPWrapper.class);
+        if (xto == RNull.instance) {
+            return xto;
+        }
+        CharSXPWrapper chw = (CharSXPWrapper) xto;
+        return VectorWrapper.get(chw);
     }
 
     @Override
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 1075ab3f63..27448accd6 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_Context.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Context.java
index 65330af2da..c48bb4886a 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Context.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Context.java
@@ -86,6 +86,10 @@ final class TruffleLLVM_Context extends RFFIContext {
 
         String libzPath = LibPaths.getBuiltinLibPath("z");
         TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(libzPath, false, true);
+
+        // String curlPath = LibPaths.getBuiltinLibPath("curl.4");
+        String curlPath = "libcurl.dylib";
+        TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(curlPath, false, true);
     }
 
     @Override
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 dc51516b4f..ebefcef623 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
@@ -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 0000000000..1abceefade
--- /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 0000000000..05f10669c9
--- /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 0000000000..4c7f70db2c
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java
@@ -0,0 +1,66 @@
+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 dc8e816a7d..6378bf00df 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 0000000000..cbc29c664e
--- /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/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java
index 7151f48559..a576084b4f 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/fficall/src/truffle_llvm/Memory.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c
index 1f8079ac75..680d13aaad 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
@@ -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) {
diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-ar b/com.oracle.truffle.r.native/llvm_tools/llvm-ar
index 2462ea65ed..2045a4ef82 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 ee6af85450..54c0ef43ed 100755
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-c++
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-c++
@@ -31,12 +31,22 @@ 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
+  #get_llvm_tool
+  #runit $llvm_tool_bin $llvm_args
+  echo "Clang args: $llvm_args"
+  clang --version
+  clang $llvm_args
+  
+  # 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 1d88276ba5..38f1d992b0 100755
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-cc
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-cc
@@ -29,15 +29,21 @@ 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
+  #llvm_tool=clang
+  #get_llvm_tool
+  #runit $llvm_tool_bin $llvm_args
+  runit clang $llvm_args
+  # 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 084f68d2df..03bd793753 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 598bb39e40..102283405c 100644
--- a/com.oracle.truffle.r.native/llvm_tools/llvm-helper
+++ b/com.oracle.truffle.r.native/llvm_tools/llvm-helper
@@ -69,19 +69,19 @@ function analyze_args() {
     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
       ;;
      *)
      ;;
@@ -113,9 +113,10 @@ function get_llvm_tool() {
 
 
 function mem2reg_opt() {
-   llvm_tool="opt"
-   get_llvm_tool
-   runit ${llvm_tool_bin} -mem2reg $llvm_ir_file -o ${llvm_ir_file}.opt
+   #llvm_tool="opt"
+   #get_llvm_tool
+   #runit ${llvm_tool_bin} -mem2reg $llvm_ir_file -o ${llvm_ir_file}.opt
+   runit opt -mem2reg $llvm_ir_file -o ${llvm_ir_file}.opt
    rc=$?
    if [ $rc -eq 0 ]
    then
@@ -138,16 +139,19 @@ function create_bc_lib() {
     case $1 in
       -o)
         shift
-	lib=$1
+		lib=$1
+      ;;
+      -*)
+        # ignore options
       ;;
      *)
-        f=$1
+        f=$(basename $1)
      	ext=${f##*.}
-	if [ $ext == 'o' ]
-	then
-	  fn=${f%%.*}.bc
-	  bcfiles+="$fn "
-	fi
+		if [ $ext == 'o' ]
+		then
+	  		fn="$(dirname $1)/${f%%.*}.bc"
+			bcfiles+="$fn "
+		fi
      ;;
     esac
     shift
@@ -157,9 +161,68 @@ function create_bc_lib() {
 # 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
-  runit $llvm_tool_bin $bcfiles -o $lib.bc
+  #llvm_tool=llvm-link
+  #get_llvm_tool
+  #runit $llvm_tool_bin $bcfiles -o $lib.bc
+  echo "Linking $lib.bc with $bcfiles"
+  runit llvm-link $bcfiles -o $lib.bc
   runit zip -r $lib $lib.bc
   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
+	  arargs+="$fn "
+	  echo "$(basename $fn) $fullPath" >> $archObjCSVtmp
+	else
+	  arargs+="$1 "
+	fi
+     ;;
+    esac
+    shift
+  done
+
+  sort -d --field-separator=' ' --key=1 $archObjCSVtmp > $archObjCSV
+
+  # 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
+}
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 1f7f724a11..cf4b856b0a 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 970c53a91d..3b404e84df 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
@@ -662,6 +662,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++) {
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 1b3555e35b..c4f8cdc520 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
@@ -25,6 +25,15 @@ package com.oracle.truffle.r.runtime.data;
 public abstract class RObject {
 
     private Object nativeMirror;
+    /**
+     * 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;
 
     public final void setNativeMirror(Object mirror) {
         this.nativeMirror = mirror;
@@ -33,4 +42,12 @@ public abstract class RObject {
     public final Object getNativeMirror() {
         return nativeMirror;
     }
+
+    public void setNativeWrapper(Object wrapper) {
+        this.nativeWrapper = wrapper;
+    }
+
+    public Object getNativeWrapper() {
+        return this.nativeWrapper;
+    }
 }
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 1782f4b2ef..e37ea75380 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 {
-- 
GitLab