diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java
index d8522ba773cd3c17651ed7ede84c26e3ca0aa60b..ff17f75a31b843c87431e068c6495444d61ae1df 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java
@@ -27,7 +27,6 @@ import com.oracle.truffle.api.interop.MessageResolution;
 import com.oracle.truffle.api.interop.Resolve;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.ffi.impl.interop.NativePointer;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.interop.RNullMRContextState;
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
index d0249e7a18639dd18ef3faa1a91d1b44073a93b1..e551bd71487c301541e4e1a2c9a3e800f11d7453 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
@@ -39,8 +39,11 @@ import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.launcher.ConsoleHandler;
 import com.oracle.truffle.r.launcher.DelegatingConsoleHandler;
 import com.oracle.truffle.r.runtime.RInterfaceCallbacks;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.REmbedRFFI.ReadConsoleNode;
 import com.oracle.truffle.r.runtime.ffi.REmbedRFFI.WriteConsoleBaseNode;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI.WriteConsoleNode;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI.WriteErrConsoleNode;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
@@ -195,7 +198,7 @@ public final class EmbeddedConsoleHandler extends DelegatingConsoleHandler {
     private CallTarget getReadLineCallTarget() {
         if (readLineCallTarget == null) {
             readLineCallTarget = Truffle.getRuntime().createCallTarget(new RootNode(null) {
-                @Child private ReadConsoleNode readConsoleNode = RFFIFactory.getREmbedRFFI().createReadConsoleNode();
+                @Child private ReadConsoleNode readConsoleNode = ReadConsoleNode.create();
 
                 @Override
                 public Object execute(VirtualFrame frame) {
@@ -208,14 +211,14 @@ public final class EmbeddedConsoleHandler extends DelegatingConsoleHandler {
 
     private CallTarget getWriteCallTarget() {
         if (writeCallTarget == null) {
-            writeCallTarget = createWriteCallTarget(RFFIFactory.getREmbedRFFI().createWriteConsoleNode());
+            writeCallTarget = createWriteCallTarget(WriteConsoleNode.create());
         }
         return writeCallTarget;
     }
 
     private CallTarget getWriteErrCallTarget() {
         if (writeErrCallTarget == null) {
-            writeErrCallTarget = createWriteCallTarget(RFFIFactory.getREmbedRFFI().createWriteErrConsoleNode());
+            writeErrCallTarget = createWriteCallTarget(WriteErrConsoleNode.create());
         }
         return writeErrCallTarget;
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/CallToNativeNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/CallToNativeNode.java
deleted file mode 100644
index ff28a7c795dba76aa2539603df8787b36b04d72c..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/CallToNativeNode.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.common;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.InteropException;
-import com.oracle.truffle.api.interop.Message;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.interop.java.JavaInterop;
-import com.oracle.truffle.api.nodes.ExplodeLoop;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray;
-import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray;
-import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
-
-public abstract class CallToNativeNode extends Node {
-
-    @Child private Node message;
-    protected final NativeFunction function;
-
-    private CallToNativeNode(NativeFunction function) {
-        this.function = function;
-    }
-
-    public CallToNativeNode create(NativeFunction f) {
-        switch (RFFIFactory.getFactoryType()) {
-            case LLVM:
-                return new NFI(f);
-            case NFI:
-                return new LLVM(f);
-            default:
-                throw RInternalError.shouldNotReachHere();
-        }
-    }
-
-    protected abstract TruffleObject getTarget();
-
-    protected final Object call(Object... args) {
-        try {
-            if (message == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                message = insert(Message.createExecute(function.getArgumentCount()).createNode());
-            }
-            wrapArguments(args);
-            return ForeignAccess.sendExecute(message, getTarget(), args);
-        } catch (InteropException e) {
-            throw RInternalError.shouldNotReachHere(e);
-        } finally {
-            finishArguments(args);
-        }
-    }
-
-    protected abstract void wrapArguments(Object[] args);
-
-    protected abstract void finishArguments(Object[] args);
-
-    private final class NFI extends CallToNativeNode {
-
-        @CompilationFinal private TruffleObject target;
-
-        private NFI(NativeFunction function) {
-            super(function);
-        }
-
-        @Override
-        protected TruffleObject getTarget() {
-            throw RInternalError.unimplemented("unused implementation");
-            // return function.getFunction();
-        }
-
-        @SuppressWarnings("cast")
-        @Override
-        @ExplodeLoop
-        protected void wrapArguments(Object[] args) {
-            for (int i = 0; i < args.length; i++) {
-                Object obj = args[i];
-                if (obj instanceof double[]) {
-                    args[i] = JavaInterop.asTruffleObject((double[]) obj);
-                } else if (obj instanceof int[] || obj == null) {
-                    args[i] = JavaInterop.asTruffleObject((int[]) obj);
-                }
-            }
-        }
-
-        @Override
-        @ExplodeLoop
-        protected void finishArguments(Object[] args) {
-            for (Object obj : args) {
-                if (obj instanceof NativeNACheck<?>) {
-                    ((NativeNACheck<?>) obj).close();
-                }
-            }
-        }
-    }
-
-    private final class LLVM extends CallToNativeNode {
-
-        @CompilationFinal private TruffleObject target;
-
-        private LLVM(NativeFunction function) {
-            super(function);
-        }
-
-        @Override
-        protected TruffleObject getTarget() {
-            if (target == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                target = DLL.findSymbol(function.getCallName(), null).asTruffleObject();
-            }
-            return target;
-        }
-
-        @Override
-        @ExplodeLoop
-        protected void wrapArguments(Object[] args) {
-            for (int i = 0; i < args.length; i++) {
-                Object obj = args[i];
-                if (obj instanceof double[]) {
-                    args[i] = new NativeDoubleArray((double[]) obj);
-                } else if (obj instanceof int[]) {
-                    args[i] = new NativeIntegerArray((int[]) obj);
-                } else if (obj == null) {
-                    args[i] = 0;
-                }
-            }
-        }
-
-        @Override
-        @ExplodeLoop
-        protected void finishArguments(Object[] args) {
-            for (Object obj : args) {
-                if (obj instanceof NativeNACheck<?>) {
-                    ((NativeNACheck<?>) obj).close();
-                }
-            }
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/DownCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/DownCallNode.java
deleted file mode 100644
index a554e2dd93ee7dfe148eaa61884fde33f9aff335..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/DownCallNode.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.common;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.InteropException;
-import com.oracle.truffle.api.interop.Message;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-
-public abstract class DownCallNode extends Node {
-
-    @Child private Node message;
-    @CompilationFinal private TruffleObject target;
-
-    protected abstract TruffleObject getTarget();
-
-    protected abstract NativeFunction getFunction();
-
-    protected final Object call(Object... args) {
-        try {
-            if (message == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                message = insert(Message.createExecute(getFunction().getArgumentCount()).createNode());
-            }
-            if (target == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                target = getTarget();
-            }
-            wrapArguments(args);
-            return ForeignAccess.sendExecute(message, target, args);
-        } catch (InteropException e) {
-            throw RInternalError.shouldNotReachHere(e);
-        } finally {
-            finishArguments(args);
-        }
-    }
-
-    protected abstract void wrapArguments(Object[] args);
-
-    protected abstract void finishArguments(Object[] args);
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/Generic_Tools.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/Generic_Tools.java
deleted file mode 100644
index 6ba135893500d83227032afcf8fd1dd69512e369..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/Generic_Tools.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.common;
-
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.conn.RConnection;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.ffi.CallRFFI;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
-import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
-
-public class Generic_Tools implements ToolsRFFI {
-    public static class Generic_ToolsRFFINode extends Node implements ParseRdNode {
-        private static final String C_PARSE_RD = "C_parseRd";
-        protected static final String TOOLS = "tools";
-
-        @Child private CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getCallRFFI().createInvokeCallNode();
-        @Child private DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
-
-        @CompilationFinal private NativeCallInfo nativeCallInfo;
-
-        /**
-         * Invoke C implementation, N.B., code is not thread safe.
-         */
-        @Override
-        public Object execute(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
-                        RLogicalVector warndups) {
-            synchronized (Generic_Tools.class) {
-                try {
-                    if (nativeCallInfo == null) {
-                        // lookup entry point (assert library is loaded)
-                        DLLInfo toolsDLLInfo = DLL.findLibrary(TOOLS);
-                        assert toolsDLLInfo != null;
-                        SymbolHandle symbolHandle = findSymbolNode.execute(C_PARSE_RD, TOOLS, DLL.RegisteredNativeSymbol.any());
-                        assert symbolHandle != DLL.SYMBOL_NOT_FOUND;
-                        nativeCallInfo = new NativeCallInfo(C_PARSE_RD, symbolHandle, toolsDLLInfo);
-                    }
-                    return callRFFINode.dispatch(nativeCallInfo,
-                                    new Object[]{con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups});
-                } catch (Throwable ex) {
-                    throw RInternalError.shouldNotReachHere(ex, "error during Rd parsing" + ex.getMessage());
-                }
-            }
-        }
-    }
-
-    @Override
-    public ParseRdNode createParseRdNode() {
-        return new Generic_ToolsRFFINode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/CharSXPWrapperMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/CharSXPWrapperMR.java
index 95c06bb5e6d83f99ec1824e1ba016a9234ac963c..f632643a7b287d73817527c8353d76afd289d44d 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/CharSXPWrapperMR.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/CharSXPWrapperMR.java
@@ -52,7 +52,7 @@ public class CharSXPWrapperMR {
 
     @Resolve(message = "HAS_SIZE")
     public abstract static class NCAHasSizeNode extends Node {
-        protected boolean access(@SuppressWarnings("unused") NativeCharArray receiver) {
+        protected boolean access(@SuppressWarnings("unused") Object receiver) {
             return true;
         }
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeIntegerArrayMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeIntegerArrayMR.java
index d92725c8fd8ea5bb3e3a1b63b8f5f258944ad4f2..aa6edfb67d5892b158eb7ef574b8a3dc00a05fcd 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeIntegerArrayMR.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeIntegerArrayMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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 com.oracle.truffle.api.interop.Resolve;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.ffi.interop.NativePointer;
 
 @MessageResolution(receiverType = NativeIntegerArray.class)
 public class NativeIntegerArrayMR {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
deleted file mode 100644
index 0f61b48a678c82be4291124847ffa9a88b9879e0..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Map;
-
-import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray;
-import com.oracle.truffle.r.ffi.impl.interop.base.ESoftVersionResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.GlobResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.ReadlinkResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.StrtolResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.UnameResult;
-import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-
-public class TruffleLLVM_Base implements BaseRFFI {
-    private static final class TruffleLLVM_GetpidNode extends TruffleLLVM_DownCallNode implements GetpidNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getpid;
-        }
-
-        @Override
-        public int execute() {
-            return (int) call();
-        }
-    }
-
-    private static class TruffleLLVM_GetwdNode extends TruffleLLVM_DownCallNode implements GetwdNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getcwd;
-        }
-
-        @Override
-        public String execute() {
-            // TODO: pass buf to "call" and do the wrapping inside wrapArguments
-            byte[] buf = new byte[4096];
-            NativeCharArray nativeBuf = new NativeCharArray(buf);
-            int result = (int) call(nativeBuf, buf.length);
-            if (result == 0) {
-                return null;
-            } else {
-                byte[] mbuf = nativeBuf.getValue();
-                int i = 0;
-                while (mbuf[i] != 0 && i < mbuf.length) {
-                    i++;
-                }
-                return new String(mbuf, 0, i);
-            }
-        }
-    }
-
-    private static class TruffleLLVM_SetwdNode extends TruffleLLVM_DownCallNode implements SetwdNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.chdir;
-        }
-
-        @Override
-        public int execute(String dir) {
-            NativeCharArray nativeBuf = new NativeCharArray(dir.getBytes());
-            return (int) call(nativeBuf);
-        }
-    }
-
-    private static class TruffleLLVM_MkdirNode extends TruffleLLVM_DownCallNode implements MkdirNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.mkdir;
-        }
-
-        @Override
-        public void execute(String dir, int mode) throws IOException {
-            NativeCharArray nativeBuf = new NativeCharArray(dir.getBytes());
-            int result = (int) call(nativeBuf, mode);
-            if (result != 0) {
-                throw new IOException("mkdir " + dir + " failed");
-            }
-        }
-    }
-
-    private static class TruffleLLVM_ReadlinkNode extends TruffleLLVM_DownCallNode implements ReadlinkNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.readlink;
-        }
-
-        private static final int EINVAL = 22;
-
-        @Override
-        public String execute(String path) throws IOException {
-            NativeCharArray nativePath = new NativeCharArray(path.getBytes());
-            ReadlinkResult callback = new ReadlinkResult();
-            call(callback, nativePath);
-            String link = callback.getLink();
-            if (link == null) {
-                if (callback.getErrno() == EINVAL) {
-                    return path;
-                } else {
-                    // some other error
-                    throw new IOException("readlink failed: " + callback.getErrno());
-                }
-            }
-            return link;
-        }
-    }
-
-    private static class TruffleLLVM_MkdtempNode extends TruffleLLVM_DownCallNode implements MkdtempNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.mkdtemp;
-        }
-
-        @Override
-        public String execute(String template) {
-            /*
-             * Not only must the (C) string end in XXXXXX it must also be null-terminated. Since it
-             * is modified by mkdtemp we must make a copy.
-             */
-            byte[] bytes = template.getBytes();
-            byte[] ztbytes = new byte[bytes.length + 1];
-            System.arraycopy(bytes, 0, ztbytes, 0, bytes.length);
-            ztbytes[bytes.length] = 0;
-            NativeCharArray nativeZtbytes = new NativeCharArray(ztbytes);
-            int result = (int) call(nativeZtbytes);
-            if (result == 0) {
-                return null;
-            } else {
-                byte[] mztBytes = nativeZtbytes.getValue();
-                return new String(mztBytes, 0, bytes.length);
-            }
-        }
-    }
-
-    private static class TruffleLLVM_ChmodNode extends TruffleLLVM_DownCallNode implements ChmodNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.chmod;
-        }
-
-        @Override
-        public int execute(String path, int mode) {
-            NativeCharArray nativePath = new NativeCharArray(path.getBytes());
-            return (int) call(nativePath, mode);
-        }
-    }
-
-    private static class TruffleLLVM_StrtolNode extends TruffleLLVM_DownCallNode implements StrtolNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.strtol;
-        }
-
-        @Override
-        public long execute(String s, int base) throws IllegalArgumentException {
-            NativeCharArray nativeString = new NativeCharArray(s.getBytes());
-            StrtolResult callback = new StrtolResult();
-            call(callback, nativeString, base);
-            if (callback.getErrno() != 0) {
-                throw new IllegalArgumentException("strtol failure");
-            } else {
-                return callback.getResult();
-            }
-        }
-    }
-
-    private static class TruffleLLVM_UnameNode extends TruffleLLVM_DownCallNode implements UnameNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.uname;
-        }
-
-        @Override
-        public UtsName execute() {
-            UnameResult baseUnameResultCallback = new UnameResult();
-            call(baseUnameResultCallback);
-            return baseUnameResultCallback;
-        }
-    }
-
-    private static class TruffleLLVM_GlobNode extends TruffleLLVM_DownCallNode implements GlobNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.glob;
-        }
-
-        @Override
-        public ArrayList<String> glob(String pattern) {
-            NativeCharArray nativePattern = new NativeCharArray(pattern.getBytes());
-            GlobResult baseGlobResultCallback = new GlobResult();
-            call(baseGlobResultCallback, nativePattern);
-            return baseGlobResultCallback.getPaths();
-        }
-    }
-
-    private static class TruffleLLVM_ESoftVersionNode extends TruffleLLVM_DownCallNode implements ESoftVersionNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.eSoftVersion;
-        }
-
-        @Override
-        public Map<String, String> eSoftVersion() {
-            ESoftVersionResult result = new ESoftVersionResult();
-            call(result);
-            return result.getVersions();
-        }
-
-    }
-
-    @Override
-    public GetpidNode createGetpidNode() {
-        return new TruffleLLVM_GetpidNode();
-    }
-
-    @Override
-    public GetwdNode createGetwdNode() {
-        return new TruffleLLVM_GetwdNode();
-    }
-
-    @Override
-    public SetwdNode createSetwdNode() {
-        return new TruffleLLVM_SetwdNode();
-    }
-
-    @Override
-    public MkdirNode createMkdirNode() {
-        return new TruffleLLVM_MkdirNode();
-    }
-
-    @Override
-    public ReadlinkNode createReadlinkNode() {
-        return new TruffleLLVM_ReadlinkNode();
-    }
-
-    @Override
-    public MkdtempNode createMkdtempNode() {
-        return new TruffleLLVM_MkdtempNode();
-    }
-
-    @Override
-    public ChmodNode createChmodNode() {
-        return new TruffleLLVM_ChmodNode();
-    }
-
-    @Override
-    public StrtolNode createStrtolNode() {
-        return new TruffleLLVM_StrtolNode();
-    }
-
-    @Override
-    public UnameNode createUnameNode() {
-        return new TruffleLLVM_UnameNode();
-    }
-
-    @Override
-    public GlobNode createGlobNode() {
-        return new TruffleLLVM_GlobNode();
-    }
-
-    @Override
-    public ESoftVersionNode createESoftVersionNode() {
-        return new TruffleLLVM_ESoftVersionNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java
index e9792234bc5f6a2b384540a3320a5036e6e41efb..496e75c66772ebe742fb085878293a364ae48a6e 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java
@@ -30,10 +30,10 @@ import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray;
 import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray;
-import com.oracle.truffle.r.ffi.impl.interop.NativeRawArray;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeRawArray;
 
 class TruffleLLVM_C implements CRFFI {
     private static class TruffleLLVM_InvokeCNode extends InvokeCNode {
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 c9365ee397a93eb2610792546e53564a89a7ce02..65330af2da6f961259a4a971e22658e46c856f6c 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
@@ -26,9 +26,17 @@ import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.r.ffi.impl.common.LibPaths;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
+import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeFunction;
+import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIContext;
+import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
+import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
+import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
 
 /**
  * A facade for the context state for the Truffle LLVM factory. Delegates to the various
@@ -36,13 +44,14 @@ import com.oracle.truffle.r.runtime.ffi.RFFIContext;
  */
 final class TruffleLLVM_Context extends RFFIContext {
 
-    final TruffleLLVM_DLL.ContextStateImpl dllState = new TruffleLLVM_DLL.ContextStateImpl();
+    private final TruffleLLVM_DLL.ContextStateImpl dllState = new TruffleLLVM_DLL.ContextStateImpl();
     final TruffleLLVM_Call.ContextStateImpl callState = new TruffleLLVM_Call.ContextStateImpl();
 
     TruffleLLVM_Context() {
-        super(new TruffleLLVM_C(), new TruffleLLVM_Base(), new TruffleLLVM_Call(), new TruffleLLVM_DLL(), new TruffleLLVM_UserRng(), new TruffleLLVM_Zip(), new TruffleLLVM_PCRE(),
-                        new TruffleLLVM_Lapack(), new TruffleLLVM_Stats(),
-                        new TruffleLLVM_Tools(), new TruffleLLVM_REmbed(), new TruffleLLVM_Misc());
+        super(new TruffleLLVM_C(), new BaseRFFI(TruffleLLVM_DownCallNodeFactory.INSTANCE), new TruffleLLVM_Call(), new TruffleLLVM_DLL(), new TruffleLLVM_UserRng(),
+                        new ZipRFFI(TruffleLLVM_DownCallNodeFactory.INSTANCE), new PCRERFFI(TruffleLLVM_DownCallNodeFactory.INSTANCE),
+                        new LapackRFFI(TruffleLLVM_DownCallNodeFactory.INSTANCE), new StatsRFFI(TruffleLLVM_DownCallNodeFactory.INSTANCE),
+                        new ToolsRFFI(), new REmbedRFFI(TruffleLLVM_DownCallNodeFactory.INSTANCE), new MiscRFFI(TruffleLLVM_DownCallNodeFactory.INSTANCE));
     }
 
     static TruffleLLVM_Context getContextState() {
@@ -67,11 +76,16 @@ final class TruffleLLVM_Context extends RFFIContext {
     @Override
     public void initializeVariables(RContext context) {
         super.initializeVariables(context);
-
         callState.initializeVariables();
-        ((TruffleLLVM_PCRE) pcreRFFI).initialize();
-        ((TruffleLLVM_Lapack) lapackRFFI).initialize();
-        ((TruffleLLVM_Zip) zipRFFI).initialize();
+
+        // Load dependencies that don't automatically get loaded:
+        TruffleLLVM_Lapack.load();
+
+        String pcrePath = LibPaths.getBuiltinLibPath("pcre");
+        TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(pcrePath, false, true);
+
+        String libzPath = LibPaths.getBuiltinLibPath("z");
+        TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(libzPath, false, true);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNode.java
deleted file mode 100644
index 9bdf1ad1c0bc344ec53f02a4bd93ea61e2c17b02..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNode.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2017, 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.llvm;
-
-import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.nodes.ExplodeLoop;
-import com.oracle.truffle.r.ffi.impl.common.DownCallNode;
-import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray;
-import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray;
-import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
-import com.oracle.truffle.r.ffi.impl.interop.NativePointer;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-
-public abstract class TruffleLLVM_DownCallNode extends DownCallNode {
-
-    @Override
-    protected final TruffleObject getTarget() {
-        CompilerAsserts.neverPartOfCompilation();
-        return DLL.findSymbol(getFunction().getCallName(), null).asTruffleObject();
-    }
-
-    @Override
-    @ExplodeLoop
-    protected void wrapArguments(Object[] args) {
-        for (int i = 0; i < args.length; i++) {
-            Object obj = args[i];
-            if (obj instanceof double[]) {
-                args[i] = new NativeDoubleArray((double[]) obj);
-            } else if (obj instanceof int[]) {
-                args[i] = new NativeIntegerArray((int[]) obj);
-            } else if (obj == null) {
-                args[i] = NativePointer.NULL_NATIVEPOINTER;
-            }
-        }
-    }
-
-    @Override
-    @ExplodeLoop
-    protected void finishArguments(Object[] args) {
-        for (Object obj : args) {
-            if (obj instanceof NativeNACheck<?>) {
-                ((NativeNACheck<?>) obj).close();
-            }
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNodeFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNodeFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..722f0a242cc963a2ee2a412ca4562e7c409ed212
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNodeFactory.java
@@ -0,0 +1,104 @@
+/*
+ * 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.llvm;
+
+import static com.oracle.truffle.r.runtime.ffi.NativeFunction.anyLibrary;
+
+import java.nio.charset.StandardCharsets;
+
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
+import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray;
+import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray;
+import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.DownCallNodeFactory;
+import com.oracle.truffle.r.runtime.ffi.NativeFunction;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray;
+import com.oracle.truffle.r.runtime.ffi.interop.NativePointer;
+
+final class TruffleLLVM_DownCallNodeFactory extends DownCallNodeFactory {
+
+    static final TruffleLLVM_DownCallNodeFactory INSTANCE = new TruffleLLVM_DownCallNodeFactory();
+
+    private TruffleLLVM_DownCallNodeFactory() {
+    }
+
+    @Override
+    public DownCallNode createDownCallNode(NativeFunction function) {
+        return new DownCallNode(function) {
+            @Override
+            protected TruffleObject getTarget(NativeFunction function) {
+                CompilerAsserts.neverPartOfCompilation();
+                String library = function.getLibrary();
+                DLLInfo dllInfo = null;
+                if (library != anyLibrary()) {
+                    dllInfo = DLL.findLibrary(library);
+                }
+                SymbolHandle result = DLL.findSymbol(function.getCallName(), dllInfo);
+                if (result == DLL.SYMBOL_NOT_FOUND) {
+                    throw RInternalError.shouldNotReachHere("Could not find function " + function.getCallName() + " in library " + library);
+                }
+                return result.asTruffleObject();
+            }
+
+            @Override
+            @ExplodeLoop
+            protected long beforeCall(NativeFunction nativeFunction, TruffleObject function, Object[] args) {
+                for (int i = 0; i < args.length; i++) {
+                    Object obj = args[i];
+                    if (obj instanceof double[]) {
+                        args[i] = new NativeDoubleArray((double[]) obj);
+                    } else if (obj instanceof int[]) {
+                        args[i] = new NativeIntegerArray((int[]) obj);
+                    } else if (obj == null) {
+                        args[i] = NativePointer.NULL_NATIVEPOINTER;
+                    } else if (obj instanceof String) {
+                        args[i] = new NativeCharArray(getStringBytes((String) obj));
+                    }
+                }
+                return 0;
+            }
+
+            @TruffleBoundary
+            private byte[] getStringBytes(String obj) {
+                return obj.getBytes(StandardCharsets.UTF_8);
+            }
+
+            @Override
+            @ExplodeLoop
+            protected void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args) {
+                for (Object obj : args) {
+                    if (obj instanceof NativeNACheck<?>) {
+                        ((NativeNACheck<?>) obj).close();
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java
index 8b0dd787556fa9ce0146288da2181acd299afa2b..30ce4603df574624ec46e549067b233f1beae106 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Lapack.java
@@ -26,8 +26,6 @@ import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.r.ffi.impl.common.LibPaths;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
-import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
 
 /**
  * When the embedded GNU R is built, LLVM is created for the components of the {@code libRblas} and
@@ -43,9 +41,9 @@ import com.oracle.truffle.r.runtime.ffi.NativeFunction;
  * when this API is requested.
  *
  */
-public class TruffleLLVM_Lapack implements LapackRFFI {
+final class TruffleLLVM_Lapack {
 
-    void initialize() {
+    static void load() {
         /*
          * This is a workaround for bad LLVM generated by DragonEgg for (some) of the Lapack
          * functions; additional spurious arguments. Unfortunately for this to be portable we would
@@ -64,8 +62,7 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
         }
 
         // The following libraries should be loaded eagerly (i.e. with the last parameter true),
-        // however,
-        // they do not load on Linux due to unbound symbols, such as "xerbla_".
+        // however, they do not load on Linux due to unbound symbols, such as "xerbla_".
         callTarget.call(LibPaths.getBuiltinLibPath("Rblas"), false, false);
         callTarget.call(LibPaths.getBuiltinLibPath("Rlapack"), false, false);
     }
@@ -78,314 +75,4 @@ public class TruffleLLVM_Lapack implements LapackRFFI {
         TruffleLLVM_NativeDLL.NativeDLOpenRootNode rootNode = TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create();
         return rootNode.getCallTarget();
     }
-
-    private static final class TruffleLLVM_IlaverNode extends TruffleLLVM_DownCallNode implements IlaverNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.ilaver;
-        }
-
-        @Override
-        public void execute(int[] version) {
-            call(version);
-        }
-    }
-
-    private static final class TruffleLLVM_DgeevNode extends TruffleLLVM_DownCallNode implements DgeevNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgeev;
-        }
-
-        @Override
-        public int execute(char jobVL, char jobVR, int n, double[] a, int lda, double[] wr, double[] wi, double[] vl, int ldvl, double[] vr, int ldvr, double[] work, int lwork) {
-            return (int) call(jobVL, jobVR, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork);
-        }
-    }
-
-    private static final class TruffleLLVM_Dgeqp3Node extends TruffleLLVM_DownCallNode implements Dgeqp3Node {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgeqp3;
-        }
-
-        @Override
-        public int execute(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork) {
-            return (int) call(m, n, a, lda, jpvt, tau, work, lwork);
-        }
-    }
-
-    private static final class TruffleLLVM_DormqrNode extends TruffleLLVM_DownCallNode implements DormqrNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dormq;
-        }
-
-        @Override
-        public int execute(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork) {
-            return (int) call(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
-        }
-    }
-
-    private static final class TruffleLLVM_DtrtrsNode extends TruffleLLVM_DownCallNode implements DtrtrsNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dtrtrs;
-        }
-
-        @Override
-        public int execute(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
-            return (int) call(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
-        }
-    }
-
-    private static final class TruffleLLVM_DgetrfNode extends TruffleLLVM_DownCallNode implements DgetrfNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgetrf;
-        }
-
-        @Override
-        public int execute(int m, int n, double[] a, int lda, int[] ipiv) {
-            return (int) call(m, n, a, lda, ipiv);
-        }
-    }
-
-    private static final class TruffleLLVM_DpotrfNode extends TruffleLLVM_DownCallNode implements DpotrfNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dpotrf;
-        }
-
-        @Override
-        public int execute(char uplo, int n, double[] a, int lda) {
-            return (int) call(uplo, n, a, lda);
-        }
-    }
-
-    private static final class TruffleLLVM_DpotriNode extends TruffleLLVM_DownCallNode implements DpotriNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dpotri;
-        }
-
-        @Override
-        public int execute(char uplo, int n, double[] a, int lda) {
-            return (int) call(uplo, n, a, lda);
-        }
-    }
-
-    private static final class TruffleLLVM_DpstrfNode extends TruffleLLVM_DownCallNode implements DpstrfNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dpstrf;
-        }
-
-        @Override
-        public int execute(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work) {
-            return (int) call(uplo, n, a, lda, piv, rank, tol, work);
-        }
-    }
-
-    private static final class TruffleLLVM_DgesvNode extends TruffleLLVM_DownCallNode implements DgesvNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgesv;
-        }
-
-        @Override
-        public int execute(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb) {
-            return (int) call(n, nrhs, a, lda, ipiv, b, ldb);
-        }
-    }
-
-    private static final class TruffleLLVM_DgesddNode extends TruffleLLVM_DownCallNode implements DgesddNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgesdd;
-        }
-
-        @Override
-        public int execute(char jobz, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldtv, double[] work, int lwork, int[] iwork) {
-            return (int) call(jobz, m, n, a, lda, s, u, ldu, vt, ldtv, work, lwork, iwork);
-        }
-    }
-
-    private static final class TruffleLLVM_DlangeNode extends TruffleLLVM_DownCallNode implements DlangeNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dlange;
-        }
-
-        @Override
-        public double execute(char norm, int m, int n, double[] a, int lda, double[] work) {
-            return (double) call(norm, m, n, a, lda, work);
-        }
-    }
-
-    private static final class TruffleLLVM_DgeconNode extends TruffleLLVM_DownCallNode implements DgeconNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgecon;
-        }
-
-        @Override
-        public int execute(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork) {
-            return (int) call(norm, n, a, lda, anorm, rcond, work, iwork);
-        }
-    }
-
-    private static final class TruffleLLVM_DsyevrNode extends TruffleLLVM_DownCallNode implements DsyevrNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dsyevr;
-        }
-
-        @Override
-        public int execute(char jobz, char range, char uplo, int n, double[] a, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, double[] w, double[] z, int ldz, int[] isuppz,
-                        double[] work, int lwork, int[] iwork, int liwork) {
-            return (int) call(jobz, range, uplo, n, a, lda, vl, vu, il, iu, abstol, m, w, z, ldz, isuppz, work, lwork, iwork, liwork);
-        }
-    }
-
-    private static final class TruffleLLVM_ZunmqrNode extends TruffleLLVM_DownCallNode implements ZunmqrNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.zunmqr;
-        }
-
-        @Override
-        public int execute(String side, String trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork) {
-            return (int) call(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
-        }
-
-    }
-
-    private static final class TruffleLLVM_ZtrtrsNode extends TruffleLLVM_DownCallNode implements ZtrtrsNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.ztrtrs;
-        }
-
-        @Override
-        public int execute(String uplo, String trans, String diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
-            return (int) call(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
-        }
-
-    }
-
-    private static final class TruffleLLVM_DtrsmNode extends TruffleLLVM_DownCallNode implements DtrsmNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dtrsm;
-        }
-
-        @Override
-        public void execute(String side, String uplo, String transa, String diag, int m, int n, double alpha, double[] a, int lda, double[] b, int ldb) {
-            call(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb);
-        }
-
-    }
-
-    @Override
-    public IlaverNode createIlaverNode() {
-        return new TruffleLLVM_IlaverNode();
-    }
-
-    @Override
-    public DgeevNode createDgeevNode() {
-        return new TruffleLLVM_DgeevNode();
-    }
-
-    @Override
-    public Dgeqp3Node createDgeqp3Node() {
-        return new TruffleLLVM_Dgeqp3Node();
-    }
-
-    @Override
-    public DormqrNode createDormqrNode() {
-        return new TruffleLLVM_DormqrNode();
-    }
-
-    @Override
-    public DtrtrsNode createDtrtrsNode() {
-        return new TruffleLLVM_DtrtrsNode();
-    }
-
-    @Override
-    public DgetrfNode createDgetrfNode() {
-        return new TruffleLLVM_DgetrfNode();
-    }
-
-    @Override
-    public DpotrfNode createDpotrfNode() {
-        return new TruffleLLVM_DpotrfNode();
-    }
-
-    @Override
-    public DpotriNode createDpotriNode() {
-        return new TruffleLLVM_DpotriNode();
-    }
-
-    @Override
-    public DpstrfNode createDpstrfNode() {
-        return new TruffleLLVM_DpstrfNode();
-    }
-
-    @Override
-    public DgesvNode createDgesvNode() {
-        return new TruffleLLVM_DgesvNode();
-    }
-
-    @Override
-    public DgesddNode createDgesddNode() {
-        return new TruffleLLVM_DgesddNode();
-    }
-
-    @Override
-    public DlangeNode createDlangeNode() {
-        return new TruffleLLVM_DlangeNode();
-    }
-
-    @Override
-    public DgeconNode createDgeconNode() {
-        return new TruffleLLVM_DgeconNode();
-    }
-
-    @Override
-    public DsyevrNode createDsyevrNode() {
-        return new TruffleLLVM_DsyevrNode();
-    }
-
-    @Override
-    public ZunmqrNode createZunmqrNode() {
-        return new TruffleLLVM_ZunmqrNode();
-    }
-
-    @Override
-    public ZtrtrsNode createZtrtrsNode() {
-        return new TruffleLLVM_ZtrtrsNode();
-    }
-
-    @Override
-    public DtrsmNode createDtrsmNode() {
-        return new TruffleLLVM_DtrsmNode();
-    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Misc.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Misc.java
deleted file mode 100644
index f30eb295eff47b3c0b73b5ddd9149f8faf03b90f..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Misc.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-
-public class TruffleLLVM_Misc implements MiscRFFI {
-
-    private static class TruffleLLVM_ExactSumNode extends TruffleLLVM_DownCallNode implements ExactSumNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.exactSumFunc;
-        }
-
-        @Override
-        public double execute(double[] values, boolean hasNa, boolean naRm) {
-            return (double) call(values, values.length, hasNa ? 1 : 0, naRm ? 1 : 0);
-        }
-    }
-
-    private static final class TruffleLLVM_DqrlsNode extends TruffleLLVM_DownCallNode implements DqrlsNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dqrls;
-        }
-
-        @Override
-        public void execute(double[] x, int n, int p, double[] y, int ny, double tol, double[] b, double[] rsd, double[] qty, int[] k, int[] jpvt, double[] qraux, double[] work) {
-            call(x, n, p, y, ny, tol, b, rsd, qty, k, jpvt, qraux, work);
-        }
-    }
-
-    @Override
-    public ExactSumNode createExactSumNode() {
-        return new TruffleLLVM_ExactSumNode();
-    }
-
-    @Override
-    public DqrlsNode createDqrlsNode() {
-        return new TruffleLLVM_DqrlsNode();
-    }
-
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_NativeDLL.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_NativeDLL.java
index 0bf28ec5788c21541caa8fb30769659f18f86faa..433b1e9c1727ed8b9356f48365f84d1fc2ebf83e 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_NativeDLL.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_NativeDLL.java
@@ -33,12 +33,12 @@ import com.oracle.truffle.api.interop.MessageResolution;
 import com.oracle.truffle.api.interop.Resolve;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.RFFIRootNode;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray;
 
 /**
  * Direct access to native {@code dlopen} for libraries for which no LLVM code is available.
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_PCRE.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_PCRE.java
deleted file mode 100644
index ce5be6d55534084ea9f6f32297251c93d5043d88..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_PCRE.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.r.ffi.impl.common.LibPaths;
-import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray;
-import com.oracle.truffle.r.ffi.impl.interop.pcre.CaptureNamesResult;
-import com.oracle.truffle.r.ffi.impl.interop.pcre.CompileResult;
-import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_Utils.AsPointerNode;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
-
-public class TruffleLLVM_PCRE implements PCRERFFI {
-
-    void initialize() {
-        // Need to ensure that the native pcre library is loaded
-        String pcrePath = LibPaths.getBuiltinLibPath("pcre");
-        TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(pcrePath, false, true);
-    }
-
-    private static class TruffleLLVM_MaketablesNode extends TruffleLLVM_DownCallNode implements MaketablesNode {
-
-        @Child private AsPointerNode asPointer = new AsPointerNode();
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.maketables;
-        }
-
-        @Override
-        public long execute() {
-            return asPointer.execute((TruffleObject) call());
-        }
-    }
-
-    private static class TruffleLLVM_GetCaptureCountNode extends TruffleLLVM_DownCallNode implements GetCaptureCountNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getcapturecount;
-        }
-
-        @Override
-        public int execute(long code, long extra) {
-            return (int) call(code, extra);
-        }
-    }
-
-    private static class TruffleLLVM_GetCaptureNamesNode extends TruffleLLVM_DownCallNode implements GetCaptureNamesNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getcapturenames;
-        }
-
-        @Override
-        public String[] execute(long code, long extra, int captureCount) {
-            CaptureNamesResult captureNamesCallback = new CaptureNamesResult(captureCount);
-            int result = (int) call(captureNamesCallback, code, extra);
-            if (result < 0) {
-                CompilerDirectives.transferToInterpreter();
-                throw RError.error(RError.NO_CALLER, RError.Message.WRONG_PCRE_INFO, result);
-            } else {
-                return captureNamesCallback.getCaptureNames();
-            }
-        }
-    }
-
-    private static class TruffleLLVM_CompileNode extends TruffleLLVM_DownCallNode implements CompileNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.compile;
-        }
-
-        @Override
-        public Result execute(String pattern, int options, long tables) {
-            NativeCharArray pattenChars = new NativeCharArray(pattern.getBytes());
-            CompileResult data = new CompileResult();
-            call(data, pattenChars, options, tables);
-            return data.getResult();
-        }
-    }
-
-    private static class TruffleLLVM_ExecNode extends TruffleLLVM_DownCallNode implements ExecNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.exec;
-        }
-
-        @Override
-        public int execute(long code, long extra, String subject, int offset, int options, int[] ovector) {
-            byte[] subjectBytes = subject.getBytes();
-            NativeCharArray subjectChars = new NativeCharArray(subjectBytes);
-            return (int) call(code, extra, subjectChars, subjectBytes.length, offset, options, ovector, ovector.length);
-        }
-    }
-
-    @Override
-    public MaketablesNode createMaketablesNode() {
-        return new TruffleLLVM_MaketablesNode();
-    }
-
-    @Override
-    public CompileNode createCompileNode() {
-        return new TruffleLLVM_CompileNode();
-    }
-
-    @Override
-    public GetCaptureCountNode createGetCaptureCountNode() {
-        return new TruffleLLVM_GetCaptureCountNode();
-    }
-
-    @Override
-    public GetCaptureNamesNode createGetCaptureNamesNode() {
-        return new TruffleLLVM_GetCaptureNamesNode();
-    }
-
-    @Override
-    public StudyNode createStudyNode() {
-        throw RInternalError.unimplemented();
-    }
-
-    @Override
-    public ExecNode createExecNode() {
-        return new TruffleLLVM_ExecNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_REmbed.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_REmbed.java
deleted file mode 100644
index 7fa4235085bc75b739e7300b48932b08d3adb697..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_REmbed.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
-
-public class TruffleLLVM_REmbed implements REmbedRFFI {
-    @Override
-    public ReadConsoleNode createReadConsoleNode() {
-        throw RInternalError.unimplemented("TODO");
-    }
-
-    @Override
-    public WriteConsoleNode createWriteConsoleNode() {
-        throw RInternalError.unimplemented("TODO");
-    }
-
-    @Override
-    public WriteErrConsoleNode createWriteErrConsoleNode() {
-        throw RInternalError.unimplemented("TODO");
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Stats.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Stats.java
deleted file mode 100644
index e2c6e30f11f817f7c9c2617e8f7e8bc755ad8374..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Stats.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.ImportStatic;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.InteropException;
-import com.oracle.truffle.api.interop.Message;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray;
-import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray;
-import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_StatsFactory.ExecuteFactorNodeGen;
-import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_StatsFactory.ExecuteWorkNodeGen;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
-import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
-
-public class TruffleLLVM_Stats implements StatsRFFI {
-
-    public enum FFT_FUN {
-        fft_work,
-        fft_factor;
-    }
-
-    public abstract static class LookupAdapter extends Node {
-        @Child private DLLRFFI.DLSymNode dllSymNode = RFFIFactory.getDLLRFFI().createDLSymNode();
-
-        public SymbolHandle lookup(String name) {
-            DLLInfo dllInfo = DLL.findLibrary("stats");
-            // cannot go through DLL because stats does not allow dynamic lookup
-            // and these symbols are not registered (only fft)
-            SymbolHandle result = dllSymNode.execute(dllInfo.handle, name);
-            if (result == DLL.SYMBOL_NOT_FOUND) {
-                throw RInternalError.shouldNotReachHere();
-            }
-            return result;
-        }
-    }
-
-    @ImportStatic({RContext.class})
-    public abstract static class ExecuteWork extends LookupAdapter {
-        public abstract int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork, RContext context);
-
-        @Specialization(guards = "context == cachedContext")
-        protected int executeWorkCached(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork, @SuppressWarnings("unused") RContext context,
-                        @SuppressWarnings("unused") @Cached("getInstance()") RContext cachedContext,
-                        @Cached("createMessageNode()") Node messageNode,
-                        @Cached("lookupWork()") SymbolHandle fftWork) {
-            return doWork(a, nseg, n, nspn, isn, work, iwork, messageNode, fftWork);
-        }
-
-        @Specialization(replaces = "executeWorkCached")
-        protected int executeWorkNormal(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork, @SuppressWarnings("unused") RContext context) {
-            return doWork(a, nseg, n, nspn, isn, work, iwork, createMessageNode(), lookup("fft_work"));
-        }
-
-        private static int doWork(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork, Node messageNode, SymbolHandle fftWork) {
-            try (NativeDoubleArray na = new NativeDoubleArray(a);
-                            NativeDoubleArray nwork = new NativeDoubleArray(work);
-                            NativeIntegerArray niwork = new NativeIntegerArray(iwork)) {
-                return (int) ForeignAccess.sendExecute(messageNode, fftWork.asTruffleObject(), na, nseg, n, nspn, isn, nwork, niwork);
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            }
-        }
-
-        public static Node createMessageNode() {
-            return Message.createExecute(7).createNode();
-        }
-
-        public static ExecuteWork create() {
-            return ExecuteWorkNodeGen.create();
-        }
-
-        public SymbolHandle lookupWork() {
-            return lookup("fft_work");
-        }
-    }
-
-    @ImportStatic({RContext.class})
-    public abstract static class ExecuteFactor extends LookupAdapter {
-        protected abstract void execute(int n, int[] pmaxf, int[] pmaxp, RContext context);
-
-        @Specialization(guards = "context == cachedContext")
-        protected void executeFactorCached(int n, int[] pmaxf, int[] pmaxp, @SuppressWarnings("unused") RContext context,
-                        @SuppressWarnings("unused") @Cached("getInstance()") RContext cachedContext,
-                        @Cached("createMessageNode()") Node messageNode,
-                        @Cached("lookupFactor()") SymbolHandle fftFactor) {
-            doFactor(n, pmaxf, pmaxp, messageNode, fftFactor);
-        }
-
-        @Specialization(replaces = "executeFactorCached")
-        protected void executeFactorNormal(int n, int[] pmaxf, int[] pmaxp, @SuppressWarnings("unused") RContext context) {
-            doFactor(n, pmaxf, pmaxp, createMessageNode(), lookup("fft_factor"));
-        }
-
-        private static void doFactor(int n, int[] pmaxf, int[] pmaxp, Node messageNode, SymbolHandle fftFactor) {
-            try (NativeIntegerArray npmaxf = new NativeIntegerArray(pmaxf);
-                            NativeIntegerArray npmaxp = new NativeIntegerArray(pmaxp)) {
-                ForeignAccess.sendExecute(messageNode, fftFactor.asTruffleObject(), n, npmaxf, npmaxp);
-            } catch (InteropException ex) {
-                throw RInternalError.shouldNotReachHere(ex);
-            }
-        }
-
-        public static Node createMessageNode() {
-            return Message.createExecute(3).createNode();
-        }
-
-        public static ExecuteFactor create() {
-            return ExecuteFactorNodeGen.create();
-        }
-
-        public SymbolHandle lookupFactor() {
-            return lookup("fft_factor");
-        }
-    }
-
-    private static class Truffle_FactorNode extends Node implements FactorNode {
-        @Child private ExecuteFactor executeFactor = ExecuteFactor.create();
-
-        @Override
-        public void execute(int n, int[] pmaxf, int[] pmaxp) {
-            executeFactor.execute(n, pmaxf, pmaxp, RContext.getInstance());
-        }
-    }
-
-    private static class Truffle_WorkNode extends Node implements WorkNode {
-        @Child private ExecuteWork executeWork = ExecuteWork.create();
-
-        @Override
-        public int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
-            return executeWork.execute(a, nseg, n, nspn, isn, work, iwork, RContext.getInstance());
-        }
-    }
-
-    private static class TruffleLLVM_LminflNode extends TruffleLLVM_DownCallNode implements LminflNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.lminfl;
-        }
-
-        @Override
-        public void execute(double[] x, int ldx, int n, int k, int docoef, double[] qraux, double[] resid, double[] hat, double[] coef, double[] sigma, double tol) {
-            call(x, ldx, n, k, docoef, qraux, resid, hat, coef, sigma, tol);
-        }
-    }
-
-    @Override
-    public FactorNode createFactorNode() {
-        return new Truffle_FactorNode();
-    }
-
-    @Override
-    public WorkNode createWorkNode() {
-        return new Truffle_WorkNode();
-    }
-
-    @Override
-    public LminflNode createLminflNode() {
-        return new TruffleLLVM_LminflNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Tools.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Tools.java
deleted file mode 100644
index 5e0d1feead4941ca78725f517ffbda4a51616428..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Tools.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import com.oracle.truffle.r.ffi.impl.common.Generic_Tools;
-import com.oracle.truffle.r.runtime.conn.RConnection;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
-
-public class TruffleLLVM_Tools implements ToolsRFFI {
-
-    private static class TruffleLLVM_ToolsRFFINode extends Generic_Tools.Generic_ToolsRFFINode {
-        /**
-         * Invoke C implementation, N.B., code is not thread safe.
-         */
-        @Override
-        public Object execute(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
-                        RLogicalVector warndups) {
-            return super.execute(con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups);
-        }
-    }
-
-    @Override
-    public ParseRdNode createParseRdNode() {
-        return new TruffleLLVM_ToolsRFFINode();
-    }
-}
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 e1d6e40f1ca421fb2303eb2fe27af8dc97847ae6..d6a1f4b67f5d8153fc01a3d1bf6abb775ef4b247 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
@@ -29,7 +29,6 @@ import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.ffi.impl.common.JavaUpCallsRFFIImpl;
 import com.oracle.truffle.r.ffi.impl.common.RFFIUtils;
-import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray;
 import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks;
 import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode;
 import com.oracle.truffle.r.runtime.REnvVars;
@@ -46,6 +45,7 @@ import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.CEntry;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray;
 
 /**
  * (Incomplete) Variant of {@link JavaUpCallsRFFIImpl} for Truffle LLVM.
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Zip.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Zip.java
deleted file mode 100644
index b6922d7ec1c89d39a6d501a8c52c5dea829aa46e..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Zip.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.llvm;
-
-import com.oracle.truffle.r.ffi.impl.common.LibPaths;
-import com.oracle.truffle.r.ffi.impl.interop.NativeRawArray;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
-
-public class TruffleLLVM_Zip implements ZipRFFI {
-
-    void initialize() {
-        // Need to ensure that the native libz library is loaded
-        String libzPath = LibPaths.getBuiltinLibPath("z");
-        TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(libzPath, false, true);
-    }
-
-    private static class TruffleLLVM_CompressNode extends TruffleLLVM_DownCallNode implements CompressNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.compress;
-        }
-
-        @Override
-        public int execute(byte[] dest, byte[] source) {
-            NativeRawArray nativeDest = new NativeRawArray(dest);
-            NativeRawArray nativeSource = new NativeRawArray(source);
-            try {
-                return (int) call(nativeDest, dest.length, nativeSource, source.length);
-            } finally {
-                nativeDest.getValue();
-            }
-        }
-    }
-
-    private static class TruffleLLVM_UncompressNode extends TruffleLLVM_DownCallNode implements UncompressNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.uncompress;
-        }
-
-        @Override
-        public int execute(byte[] dest, byte[] source) {
-            NativeRawArray nativeDest = new NativeRawArray(dest);
-            NativeRawArray nativeSource = new NativeRawArray(source);
-            try {
-                return (int) call(nativeDest, dest.length, nativeSource, source.length);
-            } finally {
-                nativeDest.getValue();
-            }
-        }
-    }
-
-    @Override
-    public CompressNode createCompressNode() {
-        return new TruffleLLVM_CompressNode();
-    }
-
-    @Override
-    public UncompressNode createUncompressNode() {
-        return new TruffleLLVM_UncompressNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
deleted file mode 100644
index a1280ebd9b70b973f6ccb6d4c1d772b1de1350d6..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2017, 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.managed;
-
-import static com.oracle.truffle.r.ffi.impl.managed.FilesystemUtils.permissionsFromMode;
-import static com.oracle.truffle.r.ffi.impl.managed.Managed_RFFIFactory.unsupported;
-
-import java.io.IOException;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.PosixFilePermissions;
-import java.util.Set;
-
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RError.Message;
-import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
-
-public class Managed_Base implements BaseRFFI {
-
-    private static final class ManagedGetpidNode extends Node implements GetpidNode {
-        private int fakePid = (int) System.currentTimeMillis();
-
-        @Override
-        public int execute() {
-            return fakePid;
-        }
-    }
-
-    /**
-     * Process id is used as seed for random number generator. We return another "random" number.
-     */
-    @Override
-    public GetpidNode createGetpidNode() {
-        return new ManagedGetpidNode();
-    }
-
-    private static final class ManagedGetwdNode extends Node implements GetwdNode {
-        @Override
-        @TruffleBoundary
-        public String execute() {
-            return Paths.get(".").toAbsolutePath().normalize().toString();
-        }
-    }
-
-    @Override
-    public GetwdNode createGetwdNode() {
-        return new ManagedGetwdNode();
-    }
-
-    private static final class ManagedSetwdNode extends Node implements SetwdNode {
-        @Override
-        public int execute(String dir) {
-            throw unsupported("setwd");
-        }
-    }
-
-    @Override
-    public SetwdNode createSetwdNode() {
-        return new ManagedSetwdNode();
-    }
-
-    private static final class ManagedMkdirNode extends Node implements MkdirNode {
-        @Override
-        @TruffleBoundary
-        public void execute(String dir, int mode) throws IOException {
-            Set<PosixFilePermission> permissions = permissionsFromMode(mode);
-            Files.createDirectories(Paths.get(dir), PosixFilePermissions.asFileAttribute(permissions));
-        }
-    }
-
-    @Override
-    public MkdirNode createMkdirNode() {
-        return new ManagedMkdirNode();
-    }
-
-    private static final class ManagedReadLinkNode extends Node implements ReadlinkNode {
-        @Override
-        public String execute(String path) throws IOException {
-            throw unsupported("linknode");
-        }
-    }
-
-    @Override
-    public ReadlinkNode createReadlinkNode() {
-        return new ManagedReadLinkNode();
-    }
-
-    private static final class ManagedMkdtempNode extends Node implements MkdtempNode {
-        @Override
-        @TruffleBoundary
-        public String execute(String template) {
-            Path path = null;
-            boolean done = false;
-            while (!done) {
-                try {
-                    path = Paths.get(template);
-                    Files.createDirectories(path);
-                    done = true;
-                } catch (FileAlreadyExistsException e) {
-                    // nop
-                } catch (IOException e) {
-                    throw RError.error(RError.NO_CALLER, Message.GENERIC, "Cannot create temp directories.");
-                }
-            }
-            return path.toString();
-        }
-    }
-
-    @Override
-    public MkdtempNode createMkdtempNode() {
-        return new ManagedMkdtempNode();
-    }
-
-    private static final class ManagedChmodNode extends Node implements ChmodNode {
-        @Override
-        @TruffleBoundary
-        public int execute(String path, int mode) {
-            try {
-                Files.setPosixFilePermissions(Paths.get(path), permissionsFromMode(mode));
-                return mode;
-            } catch (IOException e) {
-                throw RError.error(RError.NO_CALLER, Message.GENERIC, "Cannot change file permissions.");
-            }
-        }
-    }
-
-    @Override
-    public ChmodNode createChmodNode() {
-        return new ManagedChmodNode();
-    }
-
-    @Override
-    public StrtolNode createStrtolNode() {
-        return null;
-    }
-
-    private static final class ManagedUnameNode extends Node implements UnameNode {
-        @Override
-        public UtsName execute() {
-            return new UtsName() {
-                @Override
-                public String sysname() {
-                    return System.getProperty("os.name");
-                }
-
-                @Override
-                public String release() {
-                    return "";
-                }
-
-                @Override
-                public String version() {
-                    return System.getProperty("os.version");
-                }
-
-                @Override
-                public String machine() {
-                    return System.getProperty("os.arch");
-                }
-
-                @Override
-                public String nodename() {
-                    return "";
-                }
-            };
-        }
-    }
-
-    @Override
-    public UnameNode createUnameNode() {
-        return new ManagedUnameNode();
-    }
-
-    @Override
-    public GlobNode createGlobNode() {
-        return null;
-    }
-
-    @Override
-    public ESoftVersionNode createESoftVersionNode() {
-        return null;
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..13eb6601ce8a4908d412362f3b9261621aa06d2d
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
@@ -0,0 +1,205 @@
+/*
+ * 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.managed;
+
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.ForeignAccess.StandardFactory;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.ffi.DownCallNodeFactory;
+import com.oracle.truffle.r.runtime.ffi.NativeFunction;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray;
+
+public final class Managed_DownCallNodeFactory extends DownCallNodeFactory {
+
+    static final Managed_DownCallNodeFactory INSTANCE = new Managed_DownCallNodeFactory();
+
+    private Managed_DownCallNodeFactory() {
+    }
+
+    @Override
+    public DownCallNode createDownCallNode(NativeFunction function) {
+        return new DownCallNode(function) {
+            @Override
+            protected TruffleObject getTarget(NativeFunction function) {
+                if (function == NativeFunction.getpid) {
+                    return new GetPID();
+                } else if (function == NativeFunction.mkdtemp) {
+                    return new Mkdtemp();
+                } else if (function == NativeFunction.getcwd) {
+                    return new Getwd();
+                }
+                return new DummyFunctionObject(function);
+            }
+
+            @Override
+            protected long beforeCall(NativeFunction nativeFunction, TruffleObject function, Object[] args) {
+                // Report unsupported functions at invocation time
+                if (function instanceof DummyFunctionObject) {
+                    throw Managed_RFFIFactory.unsupported(((DummyFunctionObject) function).function.getCallName());
+                }
+                return 0;
+            }
+
+            @Override
+            protected void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args) {
+                // nop
+            }
+        };
+    }
+
+    private static final class DummyFunctionObject implements TruffleObject {
+        final NativeFunction function;
+
+        private DummyFunctionObject(NativeFunction function) {
+            this.function = function;
+        }
+
+        @Override
+        public ForeignAccess getForeignAccess() {
+            return null;
+        }
+    }
+
+    // PID is used as a seed for random numbers generation. We still want to support random numbers
+    // in managed mode so we make up some (random) value
+    private static final class GetPID implements TruffleObject {
+        private static final int fakePid = (int) System.currentTimeMillis();
+
+        @Override
+        public ForeignAccess getForeignAccess() {
+            return ForeignAccess.create(GetPID.class, new StandardFactory() {
+                @Override
+                public CallTarget accessIsExecutable() {
+                    return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(true));
+                }
+
+                @Override
+                public CallTarget accessExecute(int argumentsLength) {
+                    return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(fakePid));
+                }
+            });
+        }
+    }
+
+    /**
+     * Implements simplified version of the {@code mkdtemp} from {@code stdlib}. The reason why we
+     * do not use only Java version is that the real {@code mkdtemp} seems to be more reliable and
+     * secure.
+     */
+    private static final class Mkdtemp implements TruffleObject {
+        private static final FileAttribute<Set<PosixFilePermission>> irwxuPermissions = PosixFilePermissions.asFileAttribute(
+                        EnumSet.of(PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE));
+
+        @Override
+        public ForeignAccess getForeignAccess() {
+            return ForeignAccess.create(GetPID.class, new StandardFactory() {
+                @Override
+                public CallTarget accessIsExecutable() {
+                    return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(true));
+                }
+
+                @Override
+                public CallTarget accessExecute(int argumentsLength) {
+                    return Truffle.getRuntime().createCallTarget(new RootNode(null) {
+                        @Override
+                        public Object execute(VirtualFrame frame) {
+                            NativeCharArray templateBytes = (NativeCharArray) ForeignAccess.getArguments(frame).get(0);
+                            String template = new String(templateBytes.getValue(), 0, templateBytes.getValue().length - 1);
+                            if (!template.endsWith("XXXXXX")) {
+                                throw new IllegalArgumentException("template must end with XXXXXX");
+                            }
+                            String templatePrefix = template.substring(0, template.length() - 6);
+                            Path path = null;
+                            int counter = 0;
+                            boolean done = false;
+                            while (!done) {
+                                try {
+                                    path = Paths.get(templatePrefix + String.format("%06d", counter++));
+                                    if (Files.exists(path)) {
+                                        continue;
+                                    }
+                                    Files.createDirectories(path, irwxuPermissions);
+                                    done = true;
+                                } catch (FileAlreadyExistsException e) {
+                                    // nop
+                                } catch (IOException e) {
+                                    throw RError.error(RError.NO_CALLER, Message.GENERIC, "Cannot create temp directories.");
+                                }
+                            }
+                            byte[] resultBytes = path.toString().getBytes();
+                            System.arraycopy(resultBytes, 0, templateBytes.getValue(), 0, Math.min(resultBytes.length, templateBytes.getValue().length));
+                            return 1;
+                        }
+                    });
+                }
+            });
+        }
+    }
+
+    /**
+     * Gives the current working directory. For some reasons, this is not exactly equivalent to
+     * calling the C function, which manifests itself during codetools package installation.
+     */
+    private static final class Getwd implements TruffleObject {
+        @Override
+        public ForeignAccess getForeignAccess() {
+            return ForeignAccess.create(GetPID.class, new StandardFactory() {
+                @Override
+                public CallTarget accessIsExecutable() {
+                    return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(true));
+                }
+
+                @Override
+                public CallTarget accessExecute(int argumentsLength) {
+                    return Truffle.getRuntime().createCallTarget(new RootNode(null) {
+                        @Override
+                        public Object execute(VirtualFrame frame) {
+                            NativeCharArray buffer = (NativeCharArray) ForeignAccess.getArguments(frame).get(0);
+                            byte[] bytes = Paths.get(".").toAbsolutePath().normalize().toString().getBytes();
+                            System.arraycopy(bytes, 0, buffer.getValue(), 0, Math.min(bytes.length, buffer.getValue().length));
+                            return 1;
+                        }
+                    });
+                }
+            });
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_LapackRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_LapackRFFI.java
deleted file mode 100644
index bc1cb7872eb6887d04a9ec7a0915c20b7024fe41..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_LapackRFFI.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2017, 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.managed;
-
-import static com.oracle.truffle.r.ffi.impl.managed.Managed_RFFIFactory.unsupported;
-
-import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
-
-public class Managed_LapackRFFI implements LapackRFFI {
-    @Override
-    public IlaverNode createIlaverNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DgeevNode createDgeevNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public Dgeqp3Node createDgeqp3Node() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DormqrNode createDormqrNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DtrtrsNode createDtrtrsNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DgetrfNode createDgetrfNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DpotrfNode createDpotrfNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DpotriNode createDpotriNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DpstrfNode createDpstrfNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DgesvNode createDgesvNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DgesddNode createDgesddNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DlangeNode createDlangeNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DgeconNode createDgeconNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DsyevrNode createDsyevrNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public ZunmqrNode createZunmqrNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public ZtrtrsNode createZtrtrsNode() {
-        throw unsupported("lapack");
-    }
-
-    @Override
-    public DtrsmNode createDtrsmNode() {
-        throw unsupported("lapack");
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_PCRERFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_PCRERFFI.java
deleted file mode 100644
index 7fe533a23ff5cf7b179199facffb450a39ae81ea..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_PCRERFFI.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.managed;
-
-import static com.oracle.truffle.r.ffi.impl.managed.Managed_RFFIFactory.unsupported;
-
-import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
-
-public class Managed_PCRERFFI implements PCRERFFI {
-    @Override
-    public MaketablesNode createMaketablesNode() {
-        throw unsupported("PCRE");
-    }
-
-    @Override
-    public CompileNode createCompileNode() {
-        throw unsupported("PCRE");
-    }
-
-    @Override
-    public GetCaptureCountNode createGetCaptureCountNode() {
-        throw unsupported("PCRE");
-    }
-
-    @Override
-    public GetCaptureNamesNode createGetCaptureNamesNode() {
-        throw unsupported("PCRE");
-    }
-
-    @Override
-    public StudyNode createStudyNode() {
-        throw unsupported("PCRE");
-    }
-
-    @Override
-    public ExecNode createExecNode() {
-        throw unsupported("PCRE");
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_REmbedRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_REmbedRFFI.java
deleted file mode 100644
index 7a99eaba80463fa098dee79c767c50859c3268be..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_REmbedRFFI.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2017, 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.managed;
-
-import static com.oracle.truffle.r.ffi.impl.managed.Managed_RFFIFactory.unsupported;
-
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
-
-public class Managed_REmbedRFFI implements REmbedRFFI {
-    @Override
-    public ReadConsoleNode createReadConsoleNode() {
-        throw unsupported("REmbed");
-    }
-
-    @Override
-    public WriteConsoleNode createWriteConsoleNode() {
-        throw unsupported("REmbed");
-    }
-
-    @Override
-    public WriteErrConsoleNode createWriteErrConsoleNode() {
-        throw unsupported("REmbed");
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java
index 2e4f6ad6a48b23c12c8605e1adda92724b0acbf5..3d32fdf2838e08d6b5e1c1c9bf0587a980b3d2c0 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java
@@ -28,12 +28,16 @@ import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI.HandleUpCallExceptionNode;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
+import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeFunction;
+import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
@@ -54,7 +58,7 @@ public final class Managed_RFFIFactory extends RFFIFactory {
                 public InvokeCNode createInvokeCNode() {
                     throw unsupported("invoke");
                 }
-            }, new Managed_Base(), new CallRFFI() {
+            }, new BaseRFFI(Managed_DownCallNodeFactory.INSTANCE), new CallRFFI() {
                 @Override
                 public InvokeCallNode createInvokeCallNode() {
                     throw unsupported("native code invocation");
@@ -104,51 +108,12 @@ public final class Managed_RFFIFactory extends RFFIFactory {
                 public SeedsNode createSeedsNode() {
                     throw unsupported("user defined RNG");
                 }
-            }, new ZipRFFI() {
-                @Override
-                public CompressNode createCompressNode() {
-                    throw unsupported("zip compression");
-                }
-
-                @Override
-                public UncompressNode createUncompressNode() {
-                    throw unsupported("zip decompression");
-                }
-            }, new Managed_PCRERFFI(), new Managed_LapackRFFI(),
-                            new StatsRFFI() {
-                                @Override
-                                public FactorNode createFactorNode() {
-                                    throw unsupported("factor");
-                                }
-
-                                @Override
-                                public WorkNode createWorkNode() {
-                                    throw unsupported("work");
-                                }
-
-                                @Override
-                                public LminflNode createLminflNode() {
-                                    throw unsupported("lminfl");
-                                }
-                            }, new ToolsRFFI() {
-                                @Override
-                                public ParseRdNode createParseRdNode() {
-                                    throw unsupported("parseRD");
-                                }
-                            }, new Managed_REmbedRFFI(), new MiscRFFI() {
-                                @Override
-                                public ExactSumNode createExactSumNode() {
-                                    throw unsupported("exactsum");
-                                }
-
-                                @Override
-                                public DqrlsNode createDqrlsNode() {
-                                    throw unsupported("dqrls");
-                                }
-                            });
+            }, new ZipRFFI(Managed_DownCallNodeFactory.INSTANCE), new PCRERFFI(Managed_DownCallNodeFactory.INSTANCE), new LapackRFFI(Managed_DownCallNodeFactory.INSTANCE),
+                            new StatsRFFI(Managed_DownCallNodeFactory.INSTANCE), new ToolsRFFI(), new REmbedRFFI(Managed_DownCallNodeFactory.INSTANCE),
+                            new MiscRFFI(Managed_DownCallNodeFactory.INSTANCE));
         }
 
-        static class IgnoreUpCallExceptionNode extends Node implements HandleUpCallExceptionNode {
+        private static class IgnoreUpCallExceptionNode extends Node implements HandleUpCallExceptionNode {
             @Override
             public void execute(Throwable ex) {
                 // nop
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/HandleNFIUpCallExceptionNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/HandleNFIUpCallExceptionNode.java
index b1620ab0921265178c6b4adbb85c04d028369fef..4c3835c1d68b5de9b9fd93ccccaa24471d3f9b1a 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/HandleNFIUpCallExceptionNode.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/HandleNFIUpCallExceptionNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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,15 +25,16 @@ package com.oracle.truffle.r.ffi.impl.nfi;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI.HandleUpCallExceptionNode;
+import com.oracle.truffle.r.runtime.ffi.DownCallNodeFactory.DownCallNode;
 import com.oracle.truffle.r.runtime.ffi.NativeFunction;
 
 public class HandleNFIUpCallExceptionNode extends Node implements HandleUpCallExceptionNode {
-    @Child private SetFlagNode setFlagNode = new SetFlagNode();
+    @Child private DownCallNode setFlagNode = TruffleNFI_DownCallNodeFactory.INSTANCE.createDownCallNode(NativeFunction.set_exception_flag);
 
     @Override
     @TruffleBoundary
     public void execute(Throwable originalEx) {
-        setFlagNode.execute();
+        setFlagNode.call();
         RuntimeException ex;
         if (originalEx instanceof RuntimeException) {
             ex = (RuntimeException) originalEx;
@@ -42,15 +43,4 @@ public class HandleNFIUpCallExceptionNode extends Node implements HandleUpCallEx
         }
         TruffleNFI_Context.getInstance().setLastUpCallException(ex);
     }
-
-    private static final class SetFlagNode extends TruffleNFI_DownCallNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.set_exception_flag;
-        }
-
-        public void execute() {
-            call();
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
deleted file mode 100644
index 7d8f8a9a8a5300fe18ec2e0fd0fbff81a0c044bc..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * 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
- * 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.nfi;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Map;
-
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.interop.java.JavaInterop;
-import com.oracle.truffle.r.ffi.impl.interop.base.ESoftVersionResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.GlobResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.ReadlinkResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.StrtolResult;
-import com.oracle.truffle.r.ffi.impl.interop.base.UnameResult;
-import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-
-public class TruffleNFI_Base implements BaseRFFI {
-
-    private static class TruffleNFI_GetpidNode extends TruffleNFI_DownCallNode implements GetpidNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getpid;
-        }
-
-        @Override
-        public int execute() {
-            return (int) call();
-        }
-    }
-
-    private static final class TruffleNFI_GetwdNode extends TruffleNFI_DownCallNode implements GetwdNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getcwd;
-        }
-
-        @TruffleBoundary
-        @Override
-        public String execute() {
-            byte[] buf = new byte[4096];
-            int result = (int) call(JavaInterop.asTruffleObject(buf), buf.length);
-            if (result == 0) {
-                return null;
-            } else {
-                int i = 0;
-                while (buf[i] != 0 && i < buf.length) {
-                    i++;
-                }
-                return new String(buf, 0, i);
-            }
-        }
-    }
-
-    private static class TruffleNFI_SetwdNode extends TruffleNFI_DownCallNode implements SetwdNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.chdir;
-        }
-
-        @Override
-        public int execute(String dir) {
-            return (int) call(dir);
-        }
-    }
-
-    private static class TruffleNFI_MkdirNode extends TruffleNFI_DownCallNode implements MkdirNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.mkdir;
-        }
-
-        @Override
-        public void execute(String dir, int mode) throws IOException {
-            if ((int) call(dir, mode) != 0) {
-                throw new IOException("mkdir " + dir + " failed");
-            }
-        }
-    }
-
-    private static class TruffleNFI_ReadlinkNode extends TruffleNFI_DownCallNode implements ReadlinkNode {
-        private static final int EINVAL = 22;
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.readlink;
-        }
-
-        @Override
-        public String execute(String path) throws IOException {
-            ReadlinkResult data = new ReadlinkResult();
-            call(data, path);
-            if (data.getLink() == null) {
-                if (data.getErrno() == EINVAL) {
-                    return path;
-                } else {
-                    // some other error
-                    throw new IOException("readlink failed: " + data.getErrno());
-                }
-            }
-            return data.getLink();
-        }
-    }
-
-    private static class TruffleNFI_MkdtempNode extends TruffleNFI_DownCallNode implements MkdtempNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.mkdtemp;
-        }
-
-        @TruffleBoundary
-        @Override
-        public String execute(String template) {
-            /*
-             * Not only must the (C) string end in XXXXXX it must also be null-terminated. Since it
-             * is modified by mkdtemp we must make a copy.
-             */
-            byte[] bytes = template.getBytes();
-            byte[] ztbytes = new byte[bytes.length + 1];
-            System.arraycopy(bytes, 0, ztbytes, 0, bytes.length);
-            ztbytes[bytes.length] = 0;
-            int result = (int) call(JavaInterop.asTruffleObject(ztbytes));
-            if (result == 0) {
-                return null;
-            } else {
-                return new String(ztbytes, 0, bytes.length);
-            }
-        }
-    }
-
-    private static class TruffleNFI_ChmodNode extends TruffleNFI_DownCallNode implements ChmodNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.chmod;
-        }
-
-        @Override
-        public int execute(String path, int mode) {
-            return (int) call(path, mode);
-        }
-    }
-
-    private static class TruffleNFI_StrtolNode extends TruffleNFI_DownCallNode implements StrtolNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.strtol;
-        }
-
-        @Override
-        public long execute(String s, int base) throws IllegalArgumentException {
-            StrtolResult data = new StrtolResult();
-            call(data, s, base);
-            if (data.getErrno() != 0) {
-                throw new IllegalArgumentException("strtol failure");
-            } else {
-                return data.getResult();
-            }
-        }
-    }
-
-    private static class TruffleNFI_UnameNode extends TruffleNFI_DownCallNode implements UnameNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.uname;
-        }
-
-        @Override
-        public UtsName execute() {
-            UnameResult data = new UnameResult();
-            call(data);
-            return data;
-        }
-    }
-
-    private static class TruffleNFI_GlobNode extends TruffleNFI_DownCallNode implements GlobNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.glob;
-        }
-
-        @Override
-        public ArrayList<String> glob(String pattern) {
-            GlobResult data = new GlobResult();
-            call(data, pattern);
-            return data.getPaths();
-        }
-    }
-
-    private static class TruffleNFI_ESoftVersionNode extends TruffleNFI_DownCallNode implements ESoftVersionNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.eSoftVersion;
-        }
-
-        @Override
-        public Map<String, String> eSoftVersion() {
-            ESoftVersionResult result = new ESoftVersionResult();
-            call(result);
-            return result.getVersions();
-        }
-
-    }
-
-    @Override
-    public GetpidNode createGetpidNode() {
-        return new TruffleNFI_GetpidNode();
-    }
-
-    @Override
-    public GetwdNode createGetwdNode() {
-        return new TruffleNFI_GetwdNode();
-    }
-
-    @Override
-    public SetwdNode createSetwdNode() {
-        return new TruffleNFI_SetwdNode();
-    }
-
-    @Override
-    public MkdirNode createMkdirNode() {
-        return new TruffleNFI_MkdirNode();
-    }
-
-    @Override
-    public ReadlinkNode createReadlinkNode() {
-        return new TruffleNFI_ReadlinkNode();
-    }
-
-    @Override
-    public MkdtempNode createMkdtempNode() {
-        return new TruffleNFI_MkdtempNode();
-    }
-
-    @Override
-    public ChmodNode createChmodNode() {
-        return new TruffleNFI_ChmodNode();
-    }
-
-    @Override
-    public StrtolNode createStrtolNode() {
-        return new TruffleNFI_StrtolNode();
-    }
-
-    @Override
-    public UnameNode createUnameNode() {
-        return new TruffleNFI_UnameNode();
-    }
-
-    @Override
-    public GlobNode createGlobNode() {
-        return new TruffleNFI_GlobNode();
-    }
-
-    @Override
-    public ESoftVersionNode createESoftVersionNode() {
-        return new TruffleNFI_ESoftVersionNode();
-    }
-
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
index 98bea5a094ff0a446211952b5e7dd6295edb56ba..9489dea36533d1a22dcdc453ec77aa1c149709dc 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java
@@ -185,13 +185,6 @@ public class TruffleNFI_Call implements CallRFFI {
         if (traceEnabled()) {
             traceDownCallReturn(name, result);
         }
-        TruffleNFI_Context nfiCtx = (TruffleNFI_Context) RContext.getInstance().getStateRFFI();
-        RuntimeException lastUpCallEx = nfiCtx.getLastUpCallException();
-        if (lastUpCallEx != null) {
-            CompilerDirectives.transferToInterpreter();
-            nfiCtx.setLastUpCallException(null);
-            throw lastUpCallEx;
-        }
     }
 
     @Override
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java
index affec6643ad9a42772210aefa6bc04dbc64accf4..7b4c1ecec2669cd03be24e4aa23852b22db14b1b 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java
@@ -50,13 +50,21 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
+import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
+import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeFunction;
+import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
+import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
+import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
+import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
 
 import sun.misc.Unsafe;
 
@@ -84,8 +92,10 @@ final class TruffleNFI_Context extends RFFIContext {
     private static ReentrantLock accessLock;
 
     TruffleNFI_Context() {
-        super(new TruffleNFI_C(), new TruffleNFI_Base(), new TruffleNFI_Call(), new TruffleNFI_DLL(), new TruffleNFI_UserRng(), new TruffleNFI_Zip(), new TruffleNFI_PCRE(), new TruffleNFI_Lapack(),
-                        new TruffleNFI_Stats(), new TruffleNFI_Tools(), new TruffleNFI_REmbed(), new TruffleNFI_Misc());
+        super(new TruffleNFI_C(), new BaseRFFI(TruffleNFI_DownCallNodeFactory.INSTANCE), new TruffleNFI_Call(), new TruffleNFI_DLL(), new TruffleNFI_UserRng(),
+                        new ZipRFFI(TruffleNFI_DownCallNodeFactory.INSTANCE), new PCRERFFI(TruffleNFI_DownCallNodeFactory.INSTANCE), new LapackRFFI(TruffleNFI_DownCallNodeFactory.INSTANCE),
+                        new StatsRFFI(TruffleNFI_DownCallNodeFactory.INSTANCE), new ToolsRFFI(), new REmbedRFFI(TruffleNFI_DownCallNodeFactory.INSTANCE),
+                        new MiscRFFI(TruffleNFI_DownCallNodeFactory.INSTANCE));
         // forward constructor
     }
 
@@ -337,6 +347,7 @@ final class TruffleNFI_Context extends RFFIContext {
 
     @Override
     public long beforeDowncall() {
+        assert transientAllocations.size() == 0 : "transientAllocations should have been cleared in afterDowncall";
         super.beforeDowncall();
         if (hasAccessLock) {
             acquireLock();
@@ -346,6 +357,7 @@ final class TruffleNFI_Context extends RFFIContext {
 
     @Override
     public void afterDowncall(long beforeValue) {
+        super.afterDowncall(beforeValue);
         popCallbacks(beforeValue);
         for (Long ptr : transientAllocations) {
             UnsafeAdapter.UNSAFE.freeMemory(ptr);
@@ -354,7 +366,12 @@ final class TruffleNFI_Context extends RFFIContext {
         if (hasAccessLock) {
             releaseLock();
         }
-        super.afterDowncall(beforeValue);
+        RuntimeException lastUpCallEx = getLastUpCallException();
+        if (lastUpCallEx != null) {
+            CompilerDirectives.transferToInterpreter();
+            setLastUpCallException(null);
+            throw lastUpCallEx;
+        }
     }
 
     public static TruffleNFI_Context getInstance() {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNode.java
deleted file mode 100644
index 3f0177ab38d1386c26b7c8653e25081079642f8d..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNode.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.nfi;
-
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.interop.java.JavaInterop;
-import com.oracle.truffle.api.nodes.ExplodeLoop;
-import com.oracle.truffle.r.ffi.impl.common.DownCallNode;
-import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
-
-public abstract class TruffleNFI_DownCallNode extends DownCallNode {
-
-    @Override
-    protected final TruffleObject getTarget() {
-        // TODO: this lookupNativeFunction function can exist in all FFI Contexts
-        return TruffleNFI_Context.getInstance().lookupNativeFunction(getFunction());
-    }
-
-    @SuppressWarnings("cast")
-    @Override
-    @ExplodeLoop
-    protected void wrapArguments(Object[] args) {
-        for (int i = 0; i < args.length; i++) {
-            Object obj = args[i];
-            // TODO: this could use the wrappers from LLVM
-            if (obj instanceof double[]) {
-                args[i] = JavaInterop.asTruffleObject((double[]) obj);
-            } else if (obj instanceof int[] || obj == null) {
-                args[i] = JavaInterop.asTruffleObject((int[]) obj);
-            }
-        }
-    }
-
-    @Override
-    @ExplodeLoop
-    protected void finishArguments(Object[] args) {
-        for (Object obj : args) {
-            // TODO: can this ever happen in NFI?
-            if (obj instanceof NativeNACheck<?>) {
-                ((NativeNACheck<?>) obj).close();
-            }
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNodeFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNodeFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..c54cca485f6a5db8e33ef0cbc90c815430c5c7c5
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNodeFactory.java
@@ -0,0 +1,106 @@
+/*
+ * 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.nfi;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
+import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.ffi.DownCallNodeFactory;
+import com.oracle.truffle.r.runtime.ffi.NativeFunction;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeUInt8Array;
+
+public final class TruffleNFI_DownCallNodeFactory extends DownCallNodeFactory {
+    public static final TruffleNFI_DownCallNodeFactory INSTANCE = new TruffleNFI_DownCallNodeFactory();
+
+    private TruffleNFI_DownCallNodeFactory() {
+    }
+
+    @Override
+    public DownCallNode createDownCallNode(NativeFunction function) {
+        return new DownCallNode(function) {
+            @Override
+            protected TruffleObject getTarget(NativeFunction function) {
+                // TODO: this lookupNativeFunction function can exist in all FFI Contexts
+                return TruffleNFI_Context.getInstance().lookupNativeFunction(function);
+            }
+
+            @SuppressWarnings("cast")
+            @Override
+            @ExplodeLoop
+            protected long beforeCall(NativeFunction function, TruffleObject target, Object[] args) {
+                for (int i = 0; i < args.length; i++) {
+                    Object obj = args[i];
+                    if (obj instanceof double[]) {
+                        args[i] = JavaInterop.asTruffleObject(obj);
+                    } else if (obj instanceof int[] || obj == null) {
+                        args[i] = JavaInterop.asTruffleObject(obj);
+                    } else if (obj instanceof NativeUInt8Array) {
+                        // accounts for NativeCharArray and NativeRawArray
+                        // the assumption is that getValue() gives us the actual backing array and
+                        // NFI will transfer any changes back to this array
+                        NativeUInt8Array nativeArr = (NativeUInt8Array) obj;
+                        byte[] data;
+                        if (nativeArr.fakesNullTermination()) {
+                            data = getNullTerminatedBytes(nativeArr.getValue());
+                            nativeArr.setValue(data, false);
+                        } else {
+                            data = nativeArr.getValue();
+                        }
+                        args[i] = JavaInterop.asTruffleObject(data);
+                    }
+                }
+
+                if (function.hasComplexInteraction()) {
+                    return ((TruffleNFI_Context) RContext.getInstance().getRFFI()).beforeDowncall();
+                }
+                return 0;
+            }
+
+            @TruffleBoundary
+            private byte[] getNullTerminatedBytes(byte[] data) {
+                byte[] newData = new byte[data.length + 1];
+                System.arraycopy(data, 0, newData, 0, data.length);
+                newData[data.length] = 0;
+                return newData;
+            }
+
+            @Override
+            @ExplodeLoop
+            protected void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args) {
+                if (function.hasComplexInteraction()) {
+                    ((TruffleNFI_Context) RContext.getInstance().getRFFI()).afterDowncall(before);
+                }
+
+                for (Object obj : args) {
+                    // TODO: can this ever happen in NFI?
+                    if (obj instanceof NativeNACheck<?>) {
+                        ((NativeNACheck<?>) obj).close();
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Lapack.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Lapack.java
deleted file mode 100644
index 613826464867598da3b2d9a949aa7cd87534ab3d..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Lapack.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * 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
- * 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.nfi;
-
-import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-
-public class TruffleNFI_Lapack implements LapackRFFI {
-
-    private static class TruffleNFI_IlaverNode extends TruffleNFI_DownCallNode implements IlaverNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.ilaver;
-        }
-
-        @Override
-        public void execute(int[] version) {
-            call(version);
-        }
-    }
-
-    private static class TruffleNFI_DgeevNode extends TruffleNFI_DownCallNode implements DgeevNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgeev;
-        }
-
-        @Override
-        public int execute(char jobVL, char jobVR, int n, double[] a, int lda, double[] wr, double[] wi, double[] vl, int ldvl, double[] vr, int ldvr, double[] work, int lwork) {
-            return (int) call(jobVL, jobVR, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork);
-        }
-    }
-
-    private static class TruffleNFI_Dgeqp3Node extends TruffleNFI_DownCallNode implements Dgeqp3Node {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgeqp3;
-        }
-
-        @Override
-        public int execute(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork) {
-            return (int) call(m, n, a, lda, jpvt, tau, work, lwork);
-        }
-    }
-
-    private static class TruffleNFI_DormqrNode extends TruffleNFI_DownCallNode implements DormqrNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dormq;
-        }
-
-        @Override
-        public int execute(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork) {
-            return (int) call(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
-        }
-    }
-
-    private static class TruffleNFI_DtrtrsNode extends TruffleNFI_DownCallNode implements DtrtrsNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dtrtrs;
-        }
-
-        @Override
-        public int execute(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
-            return (int) call(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
-        }
-    }
-
-    private static class TruffleNFI_DgetrfNode extends TruffleNFI_DownCallNode implements DgetrfNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgetrf;
-        }
-
-        @Override
-        public int execute(int m, int n, double[] a, int lda, int[] ipiv) {
-            return (int) call(m, n, a, lda, ipiv);
-        }
-    }
-
-    private static class TruffleNFI_DpotrfNode extends TruffleNFI_DownCallNode implements DpotrfNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dpotrf;
-        }
-
-        @Override
-        public int execute(char uplo, int n, double[] a, int lda) {
-            return (int) call(uplo, n, a, lda);
-        }
-    }
-
-    private static class TruffleNFI_DpotriNode extends TruffleNFI_DownCallNode implements DpotriNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dpotri;
-        }
-
-        @Override
-        public int execute(char uplo, int n, double[] a, int lda) {
-            return (int) call(uplo, n, a, lda);
-        }
-    }
-
-    private static class TruffleNFI_DpstrfNode extends TruffleNFI_DownCallNode implements DpstrfNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dpstrf;
-        }
-
-        @Override
-        public int execute(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work) {
-            return (int) call(uplo, n, a, lda, piv, rank, tol, work);
-        }
-    }
-
-    private static class TruffleNFI_DgesvNode extends TruffleNFI_DownCallNode implements DgesvNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgesv;
-        }
-
-        @Override
-        public int execute(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb) {
-            return (int) call(n, nrhs, a, lda, ipiv, b, ldb);
-        }
-    }
-
-    private static class TruffleNFI_DgesddNode extends TruffleNFI_DownCallNode implements DgesddNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgesdd;
-        }
-
-        @Override
-        public int execute(char jobz, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldtv, double[] work, int lwork, int[] iwork) {
-            return (int) call(jobz, m, n, a, lda, s, u, ldu, vt, ldtv, work, lwork, iwork);
-        }
-    }
-
-    private static class TruffleNFI_DlangeNode extends TruffleNFI_DownCallNode implements DlangeNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dlange;
-        }
-
-        @Override
-        public double execute(char norm, int m, int n, double[] a, int lda, double[] work) {
-            return (double) call(norm, m, n, a, lda, work);
-        }
-    }
-
-    private static class TruffleNFI_DgeconNode extends TruffleNFI_DownCallNode implements DgeconNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dgecon;
-        }
-
-        @Override
-        public int execute(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork) {
-            return (int) call(norm, n, a, lda, anorm, rcond, work, iwork);
-        }
-    }
-
-    private static class TruffleNFI_DsyevrNode extends TruffleNFI_DownCallNode implements DsyevrNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dsyevr;
-        }
-
-        @Override
-        public int execute(char jobz, char range, char uplo, int n, double[] a, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, double[] w, double[] z, int ldz, int[] isuppz,
-                        double[] work, int lwork, int[] iwork, int liwork) {
-            return (int) call(jobz, range, uplo, n, a, lda, vl, vu, il, iu, abstol, m, w, z, ldz, isuppz, work, lwork, iwork, liwork);
-        }
-    }
-
-    private static class TruffleNFI_ZunmqrNode extends TruffleNFI_DownCallNode implements ZunmqrNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.zunmqr;
-        }
-
-        @Override
-        public int execute(String side, String trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork) {
-            return (int) call(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
-        }
-
-    }
-
-    private static final class TruffleNFI_ZtrtrsNode extends TruffleNFI_DownCallNode implements ZtrtrsNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.ztrtrs;
-        }
-
-        @Override
-        public int execute(String uplo, String trans, String diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
-            return (int) call(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
-        }
-    }
-
-    private static class TruffleNFI_DtrsmNode extends TruffleNFI_DownCallNode implements DtrsmNode {
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dtrsm;
-        }
-
-        @Override
-        public void execute(String side, String uplo, String transa, String diag, int m, int n, double alpha, double[] a, int lda, double[] b, int ldb) {
-            call(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb);
-        }
-
-    }
-
-    @Override
-    public IlaverNode createIlaverNode() {
-        return new TruffleNFI_IlaverNode();
-    }
-
-    @Override
-    public DgeevNode createDgeevNode() {
-        return new TruffleNFI_DgeevNode();
-    }
-
-    @Override
-    public Dgeqp3Node createDgeqp3Node() {
-        return new TruffleNFI_Dgeqp3Node();
-    }
-
-    @Override
-    public DormqrNode createDormqrNode() {
-        return new TruffleNFI_DormqrNode();
-    }
-
-    @Override
-    public DtrtrsNode createDtrtrsNode() {
-        return new TruffleNFI_DtrtrsNode();
-    }
-
-    @Override
-    public DgetrfNode createDgetrfNode() {
-        return new TruffleNFI_DgetrfNode();
-    }
-
-    @Override
-    public DpotrfNode createDpotrfNode() {
-        return new TruffleNFI_DpotrfNode();
-    }
-
-    @Override
-    public DpotriNode createDpotriNode() {
-        return new TruffleNFI_DpotriNode();
-    }
-
-    @Override
-    public DpstrfNode createDpstrfNode() {
-        return new TruffleNFI_DpstrfNode();
-    }
-
-    @Override
-    public DgesvNode createDgesvNode() {
-        return new TruffleNFI_DgesvNode();
-    }
-
-    @Override
-    public DgesddNode createDgesddNode() {
-        return new TruffleNFI_DgesddNode();
-    }
-
-    @Override
-    public DlangeNode createDlangeNode() {
-        return new TruffleNFI_DlangeNode();
-    }
-
-    @Override
-    public DgeconNode createDgeconNode() {
-        return new TruffleNFI_DgeconNode();
-    }
-
-    @Override
-    public DsyevrNode createDsyevrNode() {
-        return new TruffleNFI_DsyevrNode();
-    }
-
-    @Override
-    public ZunmqrNode createZunmqrNode() {
-        return new TruffleNFI_ZunmqrNode();
-    }
-
-    @Override
-    public ZtrtrsNode createZtrtrsNode() {
-        return new TruffleNFI_ZtrtrsNode();
-    }
-
-    @Override
-    public DtrsmNode createDtrsmNode() {
-        return new TruffleNFI_DtrsmNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Misc.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Misc.java
deleted file mode 100644
index e94bcccd814c111c7c13e3e4a69bba301a89990f..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Misc.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.nfi;
-
-import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-
-public class TruffleNFI_Misc implements MiscRFFI {
-
-    private static final class TruffleNFI_ExactSumNode extends TruffleNFI_DownCallNode implements ExactSumNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.exactSumFunc;
-        }
-
-        @Override
-        public double execute(double[] values, boolean hasNa, boolean naRm) {
-            return (double) call(values, values.length, hasNa ? 1 : 0, naRm ? 1 : 0);
-        }
-    }
-
-    private static class TruffleNFI_DqrlsNode extends TruffleNFI_DownCallNode implements DqrlsNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.dqrls;
-        }
-
-        @Override
-        public void execute(double[] x, int n, int p, double[] y, int ny, double tol, double[] b, double[] rsd, double[] qty, int[] k, int[] jpvt, double[] qraux, double[] work) {
-            call(x, n, p, y, ny, tol, b, rsd, qty, k, jpvt, qraux, work);
-        }
-    }
-
-    @Override
-    public ExactSumNode createExactSumNode() {
-        return new TruffleNFI_ExactSumNode();
-    }
-
-    @Override
-    public DqrlsNode createDqrlsNode() {
-        return new TruffleNFI_DqrlsNode();
-    }
-
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PCRE.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PCRE.java
deleted file mode 100644
index 0be4447c546dd8d4d48125bc01feff222d0606e0..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_PCRE.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.nfi;
-
-import java.nio.charset.StandardCharsets;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.interop.java.JavaInterop;
-import com.oracle.truffle.r.ffi.impl.interop.pcre.CaptureNamesResult;
-import com.oracle.truffle.r.ffi.impl.interop.pcre.CompileResult;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
-
-public class TruffleNFI_PCRE implements PCRERFFI {
-
-    private static class TruffleNFI_MaketablesNode extends TruffleNFI_DownCallNode implements MaketablesNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.maketables;
-        }
-
-        @Override
-        public long execute() {
-            return (long) call();
-        }
-    }
-
-    private static class TruffleNFI_GetCaptureCountNode extends TruffleNFI_DownCallNode implements GetCaptureCountNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getcapturecount;
-        }
-
-        @Override
-        public int execute(long code, long extra) {
-            return (int) call(code, extra);
-        }
-    }
-
-    private static class TruffleNFI_GetCaptureNamesNode extends TruffleNFI_DownCallNode implements GetCaptureNamesNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.getcapturenames;
-        }
-
-        @Override
-        public String[] execute(long code, long extra, int captureCount) {
-            CaptureNamesResult data = new CaptureNamesResult(captureCount);
-            int result = (int) call(data, code, extra);
-            if (result < 0) {
-                CompilerDirectives.transferToInterpreter();
-                throw RError.error(RError.NO_CALLER, RError.Message.WRONG_PCRE_INFO, result);
-            } else {
-                return data.getCaptureNames();
-            }
-        }
-    }
-
-    private static class TruffleNFI_CompileNode extends TruffleNFI_DownCallNode implements CompileNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.compile;
-        }
-
-        @Override
-        public Result execute(String pattern, int options, long tables) {
-            CompileResult data = new CompileResult();
-            call(data, pattern, options, tables);
-            return data.getResult();
-        }
-    }
-
-    private static class TruffleNFI_ExecNode extends TruffleNFI_DownCallNode implements ExecNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.exec;
-        }
-
-        @Override
-        public int execute(long code, long extra, String subject, int offset, int options, int[] ovector) {
-            byte[] subjectBytes = subject.getBytes(StandardCharsets.UTF_8);
-            return (int) call(code, extra, JavaInterop.asTruffleObject(subjectBytes), subjectBytes.length, offset, options, ovector, ovector.length);
-        }
-    }
-
-    @Override
-    public MaketablesNode createMaketablesNode() {
-        return new TruffleNFI_MaketablesNode();
-    }
-
-    @Override
-    public CompileNode createCompileNode() {
-        return new TruffleNFI_CompileNode();
-    }
-
-    @Override
-    public GetCaptureCountNode createGetCaptureCountNode() {
-        return new TruffleNFI_GetCaptureCountNode();
-    }
-
-    @Override
-    public GetCaptureNamesNode createGetCaptureNamesNode() {
-        return new TruffleNFI_GetCaptureNamesNode();
-    }
-
-    @Override
-    public StudyNode createStudyNode() {
-        throw RInternalError.unimplemented();
-    }
-
-    @Override
-    public ExecNode createExecNode() {
-        return new TruffleNFI_ExecNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_REmbed.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_REmbed.java
deleted file mode 100644
index 64c70971c20435a6d83a151bbfe696cf21cc670b..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_REmbed.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2017, 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.nfi;
-
-import com.oracle.truffle.api.CompilerDirectives;
-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.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
-
-public class TruffleNFI_REmbed implements REmbedRFFI {
-
-    private static class TruffleNFI_ReadConsoleNode extends TruffleNFI_DownCallNode implements ReadConsoleNode {
-        @Child private Node unboxNode;
-
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.rembedded_read_console;
-        }
-
-        @Override
-        public String execute(String prompt) {
-            Object result = call(prompt);
-            if (result instanceof String) {
-                return (String) result;
-            }
-            assert result instanceof TruffleObject : "NFI is expected to send us TruffleObject or String";
-            if (unboxNode == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                unboxNode = insert(Message.UNBOX.createNode());
-            }
-            try {
-                return (String) ForeignAccess.sendUnbox(unboxNode, (TruffleObject) result);
-            } catch (ClassCastException | UnsupportedMessageException e) {
-                CompilerDirectives.transferToInterpreter();
-                throw RInternalError.shouldNotReachHere("Unboxing TruffleObject from NFI, which should be String wrapper, failed. " + e.getMessage());
-            }
-        }
-    }
-
-    private static class TruffleNFI_WriteConsoleNode extends TruffleNFI_DownCallNode implements WriteConsoleNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.rembedded_write_console;
-        }
-
-        @Override
-        public void execute(String x) {
-            call(x, x.length());
-        }
-    }
-
-    private static class TruffleNFI_WriteErrConsoleNode extends TruffleNFI_DownCallNode implements WriteErrConsoleNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.rembedded_write_err_console;
-        }
-
-        @Override
-        public void execute(String x) {
-            call(x, x.length());
-        }
-    }
-
-    @Override
-    public ReadConsoleNode createReadConsoleNode() {
-        return new TruffleNFI_ReadConsoleNode();
-    }
-
-    @Override
-    public WriteConsoleNode createWriteConsoleNode() {
-        return new TruffleNFI_WriteConsoleNode();
-    }
-
-    @Override
-    public WriteErrConsoleNode createWriteErrConsoleNode() {
-        return new TruffleNFI_WriteErrConsoleNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Stats.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Stats.java
deleted file mode 100644
index 86a8ce5bf347346ffc3aaf48f0908e5a5a058d50..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Stats.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.nfi;
-
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
-
-public class TruffleNFI_Stats implements StatsRFFI {
-
-    private static class TruffleNFI_FactorNode extends TruffleNFI_DownCallNode implements FactorNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.fft_factor;
-        }
-
-        @Override
-        public void execute(int n, int[] pmaxf, int[] pmaxp) {
-            call(n, pmaxf, pmaxp);
-        }
-    }
-
-    private static class TruffleNFI_WorkNode extends TruffleNFI_DownCallNode implements WorkNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.fft_work;
-        }
-
-        @Override
-        public int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
-            return (int) call(a, nseg, n, nspn, isn, work, iwork);
-        }
-    }
-
-    private static class TruffleNFI_LminflNode extends TruffleNFI_DownCallNode implements LminflNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.lminfl;
-        }
-
-        @Override
-        public void execute(double[] x, int ldx, int n, int k, int docoef, double[] qraux, double[] resid, double[] hat, double[] coef, double[] sigma, double tol) {
-            call(x, ldx, n, k, docoef, qraux, resid, hat, coef, sigma, tol);
-        }
-    }
-
-    @Override
-    public FactorNode createFactorNode() {
-        return new TruffleNFI_FactorNode();
-    }
-
-    @Override
-    public WorkNode createWorkNode() {
-        return new TruffleNFI_WorkNode();
-    }
-
-    @Override
-    public LminflNode createLminflNode() {
-        return new TruffleNFI_LminflNode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Tools.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Tools.java
deleted file mode 100644
index ca3cebfcfc3afcecddff9b59c82236f861f7267b..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Tools.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.nfi;
-
-import com.oracle.truffle.r.ffi.impl.common.Generic_Tools;
-import com.oracle.truffle.r.runtime.conn.RConnection;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
-
-public class TruffleNFI_Tools implements ToolsRFFI {
-
-    private static class TruffleNFI_ToolsRFFINode extends Generic_Tools.Generic_ToolsRFFINode {
-
-        @Override
-        public Object execute(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
-                        RLogicalVector warndups) {
-            return super.execute(con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups);
-        }
-    }
-
-    @Override
-    public ParseRdNode createParseRdNode() {
-        return new TruffleNFI_ToolsRFFINode();
-    }
-}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Zip.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Zip.java
deleted file mode 100644
index c3340a66c97ae4b8aede53b9fb21cde3e3b2dd0a..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Zip.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.ffi.impl.nfi;
-
-import com.oracle.truffle.api.interop.java.JavaInterop;
-import com.oracle.truffle.r.runtime.ffi.NativeFunction;
-import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
-
-public class TruffleNFI_Zip implements ZipRFFI {
-
-    private static class TruffleNFI_CompressNode extends TruffleNFI_DownCallNode implements ZipRFFI.CompressNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.compress;
-        }
-
-        @Override
-        public int execute(byte[] dest, byte[] source) {
-            return (int) call(JavaInterop.asTruffleObject(dest), (long) dest.length, JavaInterop.asTruffleObject(source), source.length);
-        }
-    }
-
-    private static class TruffleNFI_UncompressNode extends TruffleNFI_DownCallNode implements ZipRFFI.UncompressNode {
-        @Override
-        protected NativeFunction getFunction() {
-            return NativeFunction.uncompress;
-        }
-
-        @Override
-        public int execute(byte[] dest, byte[] source) {
-            return (int) call(JavaInterop.asTruffleObject(dest), (long) dest.length, JavaInterop.asTruffleObject(source), source.length);
-        }
-    }
-
-    @Override
-    public CompressNode createCompressNode() {
-        return new TruffleNFI_CompressNode();
-    }
-
-    @Override
-    public UncompressNode createUncompressNode() {
-        return new TruffleNFI_UncompressNode();
-    }
-}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
index 38bc4c0ad22ad375ff0353bb898501f73dfaa44d..3622ed37c173e237a26414a2e7c5b32d3601c496 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
@@ -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.
  */
@@ -27,11 +27,11 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.FileSystemUtils;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
 
@@ -46,8 +46,6 @@ public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
         casts.arg(1).asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
-    @Child private BaseRFFI.ChmodNode chmodNode = BaseRFFI.ChmodNode.create();
-
     @Specialization
     @TruffleBoundary
     protected RNull dirChmod(String pathName, boolean setGroupWrite) {
@@ -69,7 +67,7 @@ public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
                 int elementMode = Utils.intFilePermissions(pfa.permissions());
                 int newMode = Files.isDirectory(element) ? elementMode | dirMask : elementMode | fileMask;
                 // System.out.printf("path %s: old %o, new %o%n", element, elementMode, newMode);
-                chmodNode.execute(element.toString(), newMode);
+                FileSystemUtils.chmod(element.toString(), newMode);
             }
         } catch (IOException ex) {
             // ignore
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
index db79b2215ba6b5029038ba6705ce42c0bb802a79..73fc274caa466d2c1e57c5d868bebe252520076c 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
@@ -46,10 +46,6 @@ int call_base_chdir(char *dir) {
     return chdir(dir);
 }
 
-int call_base_mkdir(char *dir, int mode) {
-    return mkdir(dir, mode);
-}
-
 int call_base_mkdtemp(char *template) {
     char *r = mkdtemp(template);
     if (r == NULL) {
@@ -59,10 +55,6 @@ int call_base_mkdtemp(char *template) {
     }
 }
 
-int call_base_chmod(char *path, int mode) {
-    return chmod(path, mode);
-}
-
 void call_base_uname(void (*call_uname_setfields)(char *sysname, char *release, char *version, char *machine, char *nodename)) {
 	struct utsname name;
 
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
index 147982d7a0f0fb133b2a6ef6eb354b9f4ac199eb..2ee67837291d22f7397d77cd232ddf33f0f8de98 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
@@ -420,7 +420,7 @@ void uR_ProcessEvents(void) {
 }
 
 void uR_CleanUp(SA_TYPE x, int y, int z) {
-    return ((call_R_CleanUp) callbacks[R_CleanUp_x])(x, y, z);
+    ((call_R_CleanUp) callbacks[R_CleanUp_x])(x, y, z);
 }
 
 void (*ptr_R_Suicide)(const char *) = uR_Suicide;
@@ -503,23 +503,16 @@ void R_runHandlers(InputHandler *handlers, fd_set *mask) {
 
 // -----------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------
-// Downcalls from Java. We invoke these functions via .Call interface so that the callbacks
-// variable gets properly initialized and in general the R API is available. These functions
-// delegate to user provided C routines that may want to access the R API.
-// NOTE: those two functions are looked up by name!
+// Downcalls from Java. We invoke these functions via REmbedRFFI
 
-SEXP invokeCleanUp(SEXP x, SEXP y, SEXP z) {
-    ptr_R_CleanUp(Rf_asInteger(x), Rf_asInteger(y), Rf_asInteger(z));
-    return R_NilValue;
+void rembedded_cleanup(int x, int y, int z) {
+    ptr_R_CleanUp(x, y, z);
 }
 
-SEXP invokeSuicide(SEXP msg) {
-    ptr_R_Suicide(R_CHAR(STRING_ELT(msg, 0)));
-    return R_NilValue;
+void rembedded_suicide(char* msg) {
+    ptr_R_Suicide(msg);
 }
 
-// TODO: these 3 are not yet invoked via .Call
-
 void rembedded_write_console(char *cbuf, int len) {
     writeConsoleImpl(cbuf, len, 0);
 }
@@ -529,7 +522,7 @@ void rembedded_write_err_console(char *cbuf, int len) {
 }
 
 char* rembedded_read_console(const char* prompt) {
-    char* cbuf = malloc(sizeof(char) * 1024);
+    unsigned char* cbuf = malloc(sizeof(char) * 1024);
     int n = (*ptr_R_ReadConsole)(prompt, cbuf, 1024, 0);
     return cbuf;
 }
diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source
index 95f9650f0151d7c0d3aecf40355d88effbd5b7a7..e373ee695f6e76d7d3f8f8c4e92d1d60995352e5 100644
--- a/com.oracle.truffle.r.native/version.source
+++ b/com.oracle.truffle.r.native/version.source
@@ -1 +1 @@
-49
+50
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
index 8dacc87f84f7ace1d6b955df48b6959c128204ac..45461997df5e49761b91fe8ffce544761b4cac25 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
@@ -63,6 +63,7 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClass
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
+import com.oracle.truffle.r.runtime.FileSystemUtils;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -81,7 +82,6 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 // Much of this code was influences/transcribed from GnuR src/main/platform.c
 
@@ -1210,8 +1210,6 @@ public class FileFunctions {
             casts.arg("mode").asIntegerVector().findFirst().mapIf(intNA(), constant(0777));
         }
 
-        @Child private BaseRFFI.MkdirNode mkdirNode = BaseRFFI.MkdirNode.create();
-
         @Specialization
         @TruffleBoundary
         protected byte dirCreate(String pathIn, boolean showWarnings, boolean recursive, int octMode) {
@@ -1247,7 +1245,7 @@ public class FileFunctions {
 
         private boolean mkdir(String path, boolean showWarnings, int mode) {
             try {
-                mkdirNode.execute(path, mode);
+                FileSystemUtils.mkdir(path, mode);
                 return true;
             } catch (IOException ex) {
                 if (showWarnings) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
index 27f194f7e9031c4e03ef06dc8729b38bd3f75360..985bc810a81cc5028e3d71a67b119e224b3040f8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.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
@@ -53,6 +53,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages;
+import com.oracle.truffle.r.runtime.FileSystemUtils;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.REnvVars;
@@ -300,8 +301,6 @@ public class SysFunctions {
             casts.arg("use_umask").asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
         }
 
-        @Child private BaseRFFI.ChmodNode chmodNode = BaseRFFI.ChmodNode.create();
-
         @Specialization
         @TruffleBoundary
         protected RLogicalVector sysChmod(RAbstractStringVector pathVec, RAbstractIntVector octmode, @SuppressWarnings("unused") boolean useUmask) {
@@ -311,7 +310,7 @@ public class SysFunctions {
                 if (path.length() == 0 || RRuntime.isNA(path)) {
                     continue;
                 }
-                int result = chmodNode.execute(path, octmode.getDataAt(i % octmode.getLength()));
+                int result = FileSystemUtils.chmod(path, octmode.getDataAt(i % octmode.getLength()));
                 data[i] = RRuntime.asLogical(result == 0);
             }
             return RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR);
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/FilesystemUtils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FileSystemUtils.java
similarity index 55%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/FilesystemUtils.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FileSystemUtils.java
index 5a4a822f7aa4d7e32203f6ae8fcc0afddfdd5683..8d9a196593dcbc57fbbe798bdc4323ab6d62daaf 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/FilesystemUtils.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FileSystemUtils.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
@@ -20,16 +20,26 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.managed;
+package com.oracle.truffle.r.runtime;
 
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileAttribute;
 import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
 import java.util.EnumSet;
 import java.util.Set;
 
-class FilesystemUtils {
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.runtime.RError.Message;
+
+public class FileSystemUtils {
     private static PosixFilePermission[] permissionValues = PosixFilePermission.values();
 
-    static Set<PosixFilePermission> permissionsFromMode(int mode) {
+    private static Set<PosixFilePermission> permissionsFromMode(int mode) {
         Set<PosixFilePermission> permissions = EnumSet.noneOf(PosixFilePermission.class);
         for (int i = 0; i < permissionValues.length; i++) {
             if ((mode & (1 << (permissionValues.length - i - 1))) != 0) {
@@ -38,4 +48,20 @@ class FilesystemUtils {
         }
         return permissions;
     }
+
+    @TruffleBoundary
+    public static int chmod(String path, int mode) {
+        try {
+            Files.setPosixFilePermissions(Paths.get(path), permissionsFromMode(mode));
+            return mode;
+        } catch (IOException e) {
+            throw RError.error(RError.NO_CALLER, Message.GENERIC, "Cannot change file permissions.");
+        }
+    }
+
+    @TruffleBoundary
+    public static void mkdir(String dir, int mode) throws IOException {
+        Set<PosixFilePermission> permissions = permissionsFromMode(mode);
+        Files.createDirectory(Paths.get(dir), PosixFilePermissions.asFileAttribute(permissions));
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java
index 4d5f97ecf48f8962ac593aec7fc5e76284e0ef2a..61ddc58a29f36f818353ceb8ad4264d102d68ce8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCleanUp.java
@@ -27,6 +27,8 @@ import com.oracle.truffle.r.runtime.ffi.CallRFFI.InvokeCallNode;
 import com.oracle.truffle.r.runtime.ffi.DLL.RFindSymbolNode;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI.EmbeddedCleanUpNode;
 import com.oracle.truffle.r.runtime.gnur.SA_TYPE;
 import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
 
@@ -44,8 +46,7 @@ public abstract class RCleanUp {
     public static void cleanUp(RContext ctx, SA_TYPE saveType, int status, boolean runLast) {
         if (RInterfaceCallbacks.R_CleanUp.isOverridden()) {
             RootCallTarget invokeUserCleanup = ctx.getOrCreateCachedCallTarget(UserDefinedCleanUpRootNode.class, () -> new UserDefinedCleanUpRootNode(ctx).getCallTarget());
-            Object[] args = new Object[]{asVector(saveType.ordinal()), asVector(status), asVector(runLast ? 1 : 0)};
-            invokeUserCleanup.call(args);
+            invokeUserCleanup.call(saveType.ordinal(), status, runLast ? 1 : 0);
         } else {
             stdCleanUp(saveType, status, runLast);
         }
@@ -134,29 +135,18 @@ public abstract class RCleanUp {
         RContext.getEngine().checkAndRunStartupShutdownFunction(".Last.sys");
     }
 
-    private static RIntVector asVector(int value) {
-        return RDataFactory.createIntVectorFromScalar(value);
-    }
-
     private static final class UserDefinedCleanUpRootNode extends RootNode {
         protected UserDefinedCleanUpRootNode(RContext ctx) {
             super(null);
-            invokeCallNode = ctx.getRFFI().callRFFI.createInvokeCallNode();
+            cleanUpNode = ctx.getRFFI().embedRFFI.createEmbeddedCleanUpNode();
             Truffle.getRuntime().createCallTarget(this);
         }
 
-        private static final String SYMBOL_NAME = "invokeCleanUp";
-        @Child InvokeCallNode invokeCallNode;
-        @Child RFindSymbolNode findSymbolNode = RFindSymbolNode.create();
+        @Child private EmbeddedCleanUpNode cleanUpNode;
 
         @Override
         public Object execute(VirtualFrame frame) {
-            SymbolHandle invokeCleanUp = findSymbolNode.execute(SYMBOL_NAME, null, null);
-            if (invokeCleanUp == null) {
-                CompilerDirectives.transferToInterpreter();
-                throw RInternalError.shouldNotReachHere("Cannot find " + SYMBOL_NAME + " symbol which should be declared in Rembedded.c");
-            }
-            invokeCallNode.dispatch(new NativeCallInfo(SYMBOL_NAME, invokeCleanUp, null), frame.getArguments());
+            cleanUpNode.execute((int) frame.getArguments()[0], (int) frame.getArguments()[1], (int) frame.getArguments()[2]);
             return null;
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSuicide.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSuicide.java
index 632e7b2594bccddec8fb27cb642881f09b3823b1..18e74dc486654fc7ec677b7bf7906ea82c453c5e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSuicide.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSuicide.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.ffi.CallRFFI.InvokeCallNode;
 import com.oracle.truffle.r.runtime.ffi.DLL.RFindSymbolNode;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+import com.oracle.truffle.r.runtime.ffi.REmbedRFFI.EmbeddedSuicideNode;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public abstract class RSuicide {
@@ -73,36 +74,25 @@ public abstract class RSuicide {
         throw new ExitException(2, false);
     }
 
-    private static RStringVector asVector(String value) {
-        return RDataFactory.createStringVector(value);
-    }
-
     private static void invokeUserDefinedSuicide(RContext ctx, String msg) {
         if (ctx != null && RInterfaceCallbacks.R_Suicide.isOverridden()) {
             RootCallTarget invokeUserCleanup = ctx.getOrCreateCachedCallTarget(UserDefinedSuicideRootNode.class, () -> new UserDefinedSuicideRootNode(ctx).getCallTarget());
-            invokeUserCleanup.call(new Object[]{asVector(msg)});
+            invokeUserCleanup.call(msg);
         }
     }
 
     private static final class UserDefinedSuicideRootNode extends RootNode {
         protected UserDefinedSuicideRootNode(RContext ctx) {
             super(null);
-            invokeCallNode = ctx.getRFFI().callRFFI.createInvokeCallNode();
+            suicideNode = ctx.getRFFI().embedRFFI.createEmbeddedSuicideNode();
             Truffle.getRuntime().createCallTarget(this);
         }
 
-        private static final String SYMBOL_NAME = "invokeSuicide";
-        @Child InvokeCallNode invokeCallNode;
-        @Child RFindSymbolNode findSymbolNode = RFindSymbolNode.create();
+        @Child private EmbeddedSuicideNode suicideNode;
 
         @Override
         public Object execute(VirtualFrame frame) {
-            SymbolHandle invokeSuicide = findSymbolNode.execute(SYMBOL_NAME, null, null);
-            if (invokeSuicide == null) {
-                CompilerDirectives.transferToInterpreter();
-                throw RInternalError.shouldNotReachHere("Cannot find " + SYMBOL_NAME + " symbol which should be declared in Rembedded.c");
-            }
-            invokeCallNode.dispatch(new NativeCallInfo(SYMBOL_NAME, invokeSuicide, null), frame.getArguments());
+            suicideNode.execute((String) frame.getArguments()[0]);
             return null;
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
index 4dd512a84a0a8283b8ecb4afed0dfb7e8d053656..a6589707125cfd506561878dc0a2874844a8c0db 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
@@ -26,60 +26,96 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Map;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.NodeInterface;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import com.oracle.truffle.r.runtime.ffi.base.ESoftVersionResult;
+import com.oracle.truffle.r.runtime.ffi.base.GlobResult;
+import com.oracle.truffle.r.runtime.ffi.base.ReadlinkResult;
+import com.oracle.truffle.r.runtime.ffi.base.StrtolResult;
+import com.oracle.truffle.r.runtime.ffi.base.UnameResult;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray;
 
 /**
  * A statically typed interface to exactly those native functions required by the R {@code base}
  * package, because the functionality is not provided by the JDK. These methods do not necessarily
  * map 1-1 to a native function, they may involve the invocation of several native functions.
  */
-public interface BaseRFFI {
+public final class BaseRFFI {
 
-    interface GetpidNode extends NodeInterface {
-        int execute();
+    private final DownCallNodeFactory downCallNodeFactory;
 
-        static GetpidNode create() {
+    public BaseRFFI(DownCallNodeFactory downCallNodeFactory) {
+        this.downCallNodeFactory = downCallNodeFactory;
+    }
+
+    public static final class GetpidNode extends NativeCallNode {
+
+        private GetpidNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.getpid));
+        }
+
+        public int execute() {
+            return (int) call();
+        }
+
+        public static GetpidNode create() {
             return RFFIFactory.getBaseRFFI().createGetpidNode();
         }
     }
 
-    interface GetwdNode extends NodeInterface {
+    public static final class GetwdNode extends NativeCallNode {
+        private static final int BUFFER_LEN = 4096;
+
+        private GetwdNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.getcwd));
+        }
+
         /**
          * Returns the current working directory, in the face of calls to {@code setwd}.
          */
-        String execute();
+        public String execute() {
+            NativeCharArray nativeBuf = NativeCharArray.crateOutputBuffer(BUFFER_LEN);
+            int result = (int) call(nativeBuf, BUFFER_LEN);
+            if (result == 0) {
+                return null;
+            } else {
+                return nativeBuf.getStringFromOutputBuffer();
+            }
+        }
 
-        static GetwdNode create() {
+        public static GetwdNode create() {
             return RFFIFactory.getBaseRFFI().createGetwdNode();
         }
     }
 
-    interface SetwdNode extends NodeInterface {
+    public static final class SetwdNode extends NativeCallNode {
+
+        private SetwdNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.chdir));
+        }
+
         /**
          * Sets the current working directory to {@code dir}. (cf. Unix {@code chdir}).
          *
          * @return 0 if successful.
          */
-        int execute(String dir);
+        public int execute(String dir) {
+            return (int) call(dir);
+        }
 
-        static SetwdNode create() {
+        public static SetwdNode create() {
             return RFFIFactory.getBaseRFFI().createSetwdNode();
         }
     }
 
-    interface MkdirNode extends NodeInterface {
-        /**
-         * Create directory with given mode. Exception is thrown on error.
-         */
-        void execute(String dir, int mode) throws IOException;
+    public static final class ReadlinkNode extends NativeCallNode {
+        private static final int EINVAL = 22;
 
-        static MkdirNode create() {
-            return RFFIFactory.getBaseRFFI().createMkdirNode();
+        private ReadlinkNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.readlink));
         }
-    }
 
-    interface ReadlinkNode extends NodeInterface {
         /**
          * Try to convert a symbolic link to it's target.
          *
@@ -87,43 +123,75 @@ public interface BaseRFFI {
          * @return the target if {@code path} is a link else {@code null}
          * @throws IOException for any other error except "not a link"
          */
-        String execute(String path) throws IOException;
+        public String execute(String path) throws IOException {
+            ReadlinkResult data = new ReadlinkResult();
+            call(data, path);
+            if (data.getLink() == null) {
+                if (data.getErrno() == EINVAL) {
+                    return path;
+                } else {
+                    // some other error
+                    throw new IOException("readlink failed: " + data.getErrno());
+                }
+            }
+            return data.getLink();
+        }
 
-        static ReadlinkNode create() {
+        public static ReadlinkNode create() {
             return RFFIFactory.getBaseRFFI().createReadlinkNode();
         }
     }
 
-    interface MkdtempNode extends NodeInterface {
+    public static final class MkdtempNode extends NativeCallNode {
+
+        private MkdtempNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.mkdtemp));
+        }
+
         /**
          * Creates a temporary directory using {@code template} and return the resulting path or
          * {@code null} if error.
          */
-        String execute(String template);
+        @TruffleBoundary
+        public String execute(String template) {
+            /*
+             * Not only must the (C) string end in XXXXXX it must also be null-terminated. Since it
+             * is modified by mkdtemp we must make a copy.
+             */
+            NativeCharArray nativeZtbytes = new NativeCharArray(template);
+            int result = (int) call(nativeZtbytes);
+            if (result == 0) {
+                return null;
+            } else {
+                return nativeZtbytes.getString();
+            }
+        }
 
-        static MkdtempNode create() {
+        public static MkdtempNode create() {
             return RFFIFactory.getBaseRFFI().createMkdtempNode();
         }
     }
 
-    interface ChmodNode extends NodeInterface {
-        /**
-         * Change the file mode of {@code path}.
-         */
-        int execute(String path, int mode);
+    public static final class StrtolNode extends NativeCallNode {
 
-        static ChmodNode create() {
-            return RFFIFactory.getBaseRFFI().createChmodNode();
+        private StrtolNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.strtol));
         }
-    }
 
-    interface StrtolNode extends NodeInterface {
         /**
          * Convert string to long.
          */
-        long execute(String s, int base) throws IllegalArgumentException;
+        public long execute(String s, int base) throws IllegalArgumentException {
+            StrtolResult data = new StrtolResult();
+            call(data, s, base);
+            if (data.getErrno() != 0) {
+                throw new IllegalArgumentException("strtol failure");
+            } else {
+                return data.getResult();
+            }
+        }
 
-        static StrtolNode create() {
+        public static StrtolNode create() {
             return RFFIFactory.getBaseRFFI().createStrtolNode();
         }
     }
@@ -140,71 +208,105 @@ public interface BaseRFFI {
         String nodename();
     }
 
-    interface UnameNode extends NodeInterface {
+    public static final class UnameNode extends NativeCallNode {
+
+        private UnameNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.uname));
+        }
+
         /**
          * Return {@code utsname} info.
          */
-        UtsName execute();
+        public UtsName execute() {
+            UnameResult data = new UnameResult();
+            call(data);
+            return data;
+        }
 
-        static UnameNode create() {
+        public static UnameNode create() {
             return RFFIFactory.getBaseRFFI().createUnameNode();
         }
     }
 
-    interface GlobNode extends NodeInterface {
+    public static final class GlobNode extends NativeCallNode {
+
+        private GlobNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.glob));
+        }
+
         /**
          * Returns an array of pathnames that match {@code pattern} using the OS glob function. This
          * is done in native code because it is very hard to write in Java in the face of
          * {@code setwd}.
          */
-        ArrayList<String> glob(String pattern);
+        public ArrayList<String> glob(String pattern) {
+            GlobResult data = new GlobResult();
+            call(data, pattern);
+            return data.getPaths();
+        }
 
-        static GlobNode create() {
+        public static GlobNode create() {
             return RFFIFactory.getBaseRFFI().createGlobNode();
         }
     }
 
-    interface ESoftVersionNode extends NodeInterface {
-        Map<String, String> eSoftVersion();
+    public static final class ESoftVersionNode extends NativeCallNode {
 
-        static ESoftVersionNode create() {
-            return RFFIFactory.getBaseRFFI().createESoftVersionNode();
+        private ESoftVersionNode(DownCallNodeFactory parent) {
+            super(parent.createDownCallNode(NativeFunction.eSoftVersion));
         }
-    }
 
-    /*
-     * The RFFI implementation influences exactly what subclass of the above nodes is created. Each
-     * implementation must therefore, implement these methods that are called by the associated
-     * "public static create()" methods above.
-     */
-
-    GetpidNode createGetpidNode();
+        public Map<String, String> eSoftVersion() {
+            ESoftVersionResult result = new ESoftVersionResult();
+            call(result);
+            return result.getVersions();
+        }
 
-    GetwdNode createGetwdNode();
+        public static ESoftVersionNode create() {
+            return RFFIFactory.getBaseRFFI().createESoftVersionNode();
+        }
+    }
 
-    SetwdNode createSetwdNode();
+    public GetpidNode createGetpidNode() {
+        return new GetpidNode(downCallNodeFactory);
+    }
 
-    MkdirNode createMkdirNode();
+    public GetwdNode createGetwdNode() {
+        return new GetwdNode(downCallNodeFactory);
+    }
 
-    ReadlinkNode createReadlinkNode();
+    public SetwdNode createSetwdNode() {
+        return new SetwdNode(downCallNodeFactory);
+    }
 
-    MkdtempNode createMkdtempNode();
+    public ReadlinkNode createReadlinkNode() {
+        return new ReadlinkNode(downCallNodeFactory);
+    }
 
-    ChmodNode createChmodNode();
+    public MkdtempNode createMkdtempNode() {
+        return new MkdtempNode(downCallNodeFactory);
+    }
 
-    StrtolNode createStrtolNode();
+    public StrtolNode createStrtolNode() {
+        return new StrtolNode(downCallNodeFactory);
+    }
 
-    UnameNode createUnameNode();
+    public UnameNode createUnameNode() {
+        return new UnameNode(downCallNodeFactory);
+    }
 
-    GlobNode createGlobNode();
+    public GlobNode createGlobNode() {
+        return new GlobNode(downCallNodeFactory);
+    }
 
-    ESoftVersionNode createESoftVersionNode();
+    public ESoftVersionNode createESoftVersionNode() {
+        return new ESoftVersionNode(downCallNodeFactory);
+    }
 
     /*
      * Some functions are called from non-Truffle contexts, which requires a RootNode
      */
-
-    final class GetpidRootNode extends RFFIRootNode<GetpidNode> {
+    public static final class GetpidRootNode extends RFFIRootNode<GetpidNode> {
 
         private GetpidRootNode() {
             super(RFFIFactory.getBaseRFFI().createGetpidNode());
@@ -220,7 +322,7 @@ public interface BaseRFFI {
         }
     }
 
-    final class GetwdRootNode extends RFFIRootNode<GetwdNode> {
+    public static final class GetwdRootNode extends RFFIRootNode<GetwdNode> {
 
         private GetwdRootNode() {
             super(RFFIFactory.getBaseRFFI().createGetwdNode());
@@ -236,7 +338,7 @@ public interface BaseRFFI {
         }
     }
 
-    final class MkdtempRootNode extends RFFIRootNode<MkdtempNode> {
+    public static final class MkdtempRootNode extends RFFIRootNode<MkdtempNode> {
 
         private MkdtempRootNode() {
             super(RFFIFactory.getBaseRFFI().createMkdtempNode());
@@ -253,7 +355,7 @@ public interface BaseRFFI {
         }
     }
 
-    final class UnameRootNode extends RFFIRootNode<UnameNode> {
+    public static final class UnameRootNode extends RFFIRootNode<UnameNode> {
 
         private UnameRootNode() {
             super(RFFIFactory.getBaseRFFI().createUnameNode());
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DownCallNodeFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DownCallNodeFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..af484e9aeee40bfe2225c722bcae3ca0569b6dfd
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DownCallNodeFactory.java
@@ -0,0 +1,107 @@
+/*
+ * 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.runtime.ffi;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.InteropException;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RInternalError;
+
+/**
+ * Factory for RFFI implementation specific {@link DownCallNode} which is responsible for
+ * implementing the invocation of functions from {@link NativeFunction}.
+ */
+public abstract class DownCallNodeFactory {
+    public abstract DownCallNode createDownCallNode(NativeFunction function);
+
+    /**
+     * This node has RFFI backend (LLVM/NFI) specific implementation and its purpose is to provide
+     * functionality to invoke functions from {@link NativeFunction}.
+     */
+    public abstract static class DownCallNode extends Node {
+
+        private final NativeFunction function;
+        @Child private Node message;
+        // TODO: can this be really shared across contexts?
+        @CompilationFinal private TruffleObject target;
+
+        protected DownCallNode(NativeFunction function) {
+            assert function != null;
+            this.function = function;
+        }
+
+        /**
+         * The arguments may contain primitive java types, Strings, arrays of any primitive Java
+         * types, {@link TruffleObject}s,
+         * {@link com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray}s and
+         * {@link com.oracle.truffle.r.runtime.ffi.interop.NativeRawArray}s. {@link TruffleObject}
+         * should be passed to LLVM/NFI as is.
+         * {@link com.oracle.truffle.r.runtime.ffi.interop.NativeRawArray} and
+         * {@link com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray} have special handling in
+         * NFI where the array should be passed as Java array, not as Truffle Object.
+         */
+        public final Object call(Object... args) {
+            long before = -1;
+            try {
+                if (message == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    message = insert(Message.createExecute(function.getArgumentCount()).createNode());
+                }
+                if (target == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    target = getTarget(function);
+                }
+                before = beforeCall(function, target, args);
+                return ForeignAccess.sendExecute(message, target, args);
+            } catch (InteropException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            } finally {
+                afterCall(before, function, target, args);
+            }
+        }
+
+        /**
+         * Should return a {@link TruffleObject} that will invoke the given function upon the
+         * {@code EXECUTE} message.
+         */
+        protected abstract TruffleObject getTarget(NativeFunction function);
+
+        /**
+         * Allows to transform the arguments before the execute message is sent to the result of
+         * {@link #getTarget(NativeFunction)}.
+         */
+        protected abstract long beforeCall(NativeFunction nativeFunction, TruffleObject function, Object[] args);
+
+        /**
+         * Allows to post-process the arguments after the execute message was sent to the result of
+         * {@link #getTarget(NativeFunction)}. If the call to
+         * {@link #beforeCall(NativeFunction, TruffleObject, Object[])} was not successfull, the
+         * {@code before} parameter will have value {@code -1}.
+         */
+        protected abstract void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args);
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/LapackRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/LapackRFFI.java
index eaff8035fce6dcb980593fdf3c8c2ebfbe27a2df..ff82db0fafbdbdfb456ba01b51c91b66a6835652 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/LapackRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/LapackRFFI.java
@@ -22,232 +22,343 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.api.nodes.NodeInterface;
-
 /**
  * Collection of statically typed Lapack methods that are used in the {@code base} package. The
  * signatures match the Fortran definition with the exception that the "info" value is returned as
  * the result of the call.
+ * 
+ * The documentation for individual functions can be found in the
+ * <a href="http://www.netlib.org/lapack/explore-html">spec</a>.
  */
-public interface LapackRFFI {
-    interface IlaverNode extends NodeInterface {
-        /**
-         * Return version info, mjor, minor, patch, in {@code version}.
-         */
-        void execute(int[] version);
-
-        static IlaverNode create() {
+public final class LapackRFFI {
+    private final DownCallNodeFactory downCallNodeFactory;
+
+    public LapackRFFI(DownCallNodeFactory downCallNodeFactory) {
+        this.downCallNodeFactory = downCallNodeFactory;
+    }
+
+    public static final class IlaverNode extends NativeCallNode {
+        public static IlaverNode create() {
             return RFFIFactory.getLapackRFFI().createIlaverNode();
         }
+
+        private IlaverNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.ilaver));
+        }
+
+        public void execute(int[] version) {
+            call((Object) version);
+        }
     }
 
-    interface DgeevNode extends NodeInterface {
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/d9/d28/dgeev_8f.html">spec</a>.
-         */
-        int execute(char jobVL, char jobVR, int n, double[] a, int lda, double[] wr, double[] wi, double[] vl, int ldvl, double[] vr, int ldvr, double[] work, int lwork);
+    public static final class DgeevNode extends NativeCallNode {
 
-        static DgeevNode create() {
+        public static DgeevNode create() {
             return RFFIFactory.getLapackRFFI().createDgeevNode();
         }
+
+        private DgeevNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dgeev));
+        }
+
+        public int execute(char jobVL, char jobVR, int n, double[] a, int lda, double[] wr, double[] wi, double[] vl, int ldvl, double[] vr, int ldvr, double[] work, int lwork) {
+            return (int) call(jobVL, jobVR, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork);
+        }
     }
 
-    interface Dgeqp3Node extends NodeInterface {
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/db/de5/dgeqp3_8f.html">spec</a>.
-         */
-        int execute(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork);
+    public static final class Dgeqp3Node extends NativeCallNode {
 
-        static Dgeqp3Node create() {
+        public static Dgeqp3Node create() {
             return RFFIFactory.getLapackRFFI().createDgeqp3Node();
         }
+
+        private Dgeqp3Node(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dgeqp3));
+        }
+
+        public int execute(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork) {
+            return (int) call(m, n, a, lda, jpvt, tau, work, lwork);
+        }
     }
 
-    interface DormqrNode extends NodeInterface {
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/da/d82/dormqr_8f.html">spec</a>.
-         */
-        int execute(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork);
+    public static final class DormqrNode extends NativeCallNode {
 
-        static DormqrNode create() {
+        public static DormqrNode create() {
             return RFFIFactory.getLapackRFFI().createDormqrNode();
         }
-    }
 
-    interface DtrtrsNode extends NodeInterface {
+        private DormqrNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dormq));
+        }
 
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/d6/d6f/dtrtrs_8f.html">spec</a>.
-         */
-        int execute(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb);
+        public int execute(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork) {
+            return (int) call(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
+        }
+    }
 
-        static DtrtrsNode create() {
+    public static final class DtrtrsNode extends NativeCallNode {
+
+        public static DtrtrsNode create() {
             return RFFIFactory.getLapackRFFI().createDtrtrsNode();
         }
-    }
 
-    interface DgetrfNode extends NodeInterface {
+        private DtrtrsNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dtrtrs));
+        }
+
+        public int execute(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
+            return (int) call(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
+        }
+    }
 
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/d3/d6a/dgetrf_8f.html">spec</a>.
-         */
-        int execute(int m, int n, double[] a, int lda, int[] ipiv);
+    public static final class DgetrfNode extends NativeCallNode {
 
-        static DgetrfNode create() {
+        public static DgetrfNode create() {
             return RFFIFactory.getLapackRFFI().createDgetrfNode();
         }
-    }
 
-    interface DpotrfNode extends NodeInterface {
+        private DgetrfNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dgetrf));
+        }
 
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/d0/d8a/dpotrf_8f.html">spec</a>.
-         */
-        int execute(char uplo, int n, double[] a, int lda);
+        public int execute(int m, int n, double[] a, int lda, int[] ipiv) {
+            return (int) call(m, n, a, lda, ipiv);
+        }
+    }
 
-        static DpotrfNode create() {
+    public static final class DpotrfNode extends NativeCallNode {
+
+        public static DpotrfNode create() {
             return RFFIFactory.getLapackRFFI().createDpotrfNode();
         }
-    }
 
-    interface DpotriNode extends NodeInterface {
+        private DpotrfNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dpotrf));
+        }
 
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/d0/d8a/dpotri_8f.html">spec</a>.
-         */
-        int execute(char uplo, int n, double[] a, int lda);
+        public int execute(char uplo, int n, double[] a, int lda) {
+            return (int) call(uplo, n, a, lda);
+        }
+    }
+
+    public static final class DpotriNode extends NativeCallNode {
 
-        static DpotriNode create() {
+        public static DpotriNode create() {
             return RFFIFactory.getLapackRFFI().createDpotriNode();
         }
+
+        private DpotriNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dpotri));
+        }
+
+        public int execute(char uplo, int n, double[] a, int lda) {
+            return (int) call(uplo, n, a, lda);
+        }
     }
 
-    interface DpstrfNode extends NodeInterface {
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/dd/dad/dpstrf_8f.html">spec</a>.
-         */
-        int execute(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work);
+    public static final class DpstrfNode extends NativeCallNode {
 
-        static DpstrfNode create() {
+        public static DpstrfNode create() {
             return RFFIFactory.getLapackRFFI().createDpstrfNode();
         }
+
+        private DpstrfNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dpstrf));
+        }
+
+        public int execute(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work) {
+            return (int) call(uplo, n, a, lda, piv, rank, tol, work);
+        }
     }
 
-    interface DgesvNode extends NodeInterface {
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/d8/d72/dgesv_8f.html">spec</a>.
-         */
-        int execute(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb);
+    public static final class DgesvNode extends NativeCallNode {
 
-        static DgesvNode create() {
+        public static DgesvNode create() {
             return RFFIFactory.getLapackRFFI().createDgesvNode();
         }
+
+        private DgesvNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dgesv));
+        }
+
+        public int execute(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb) {
+            return (int) call(n, nrhs, a, lda, ipiv, b, ldb);
+        }
     }
 
-    interface DgesddNode extends NodeInterface {
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/db/db4/dgesdd_8f.html">spec</a>.
-         */
-        int execute(char jobz, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldtv, double[] work, int lwork, int[] iwork);
+    public static final class DgesddNode extends NativeCallNode {
 
-        static DgesddNode create() {
+        public static DgesddNode create() {
             return RFFIFactory.getLapackRFFI().createDgesddNode();
         }
-    }
 
-    interface DlangeNode extends NodeInterface {
+        private DgesddNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dgesdd));
+        }
+
+        public int execute(char jobz, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldtv, double[] work, int lwork, int[] iwork) {
+            return (int) call(jobz, m, n, a, lda, s, u, ldu, vt, ldtv, work, lwork, iwork);
+        }
+    }
 
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/dc/d09/dlange_8f.html">spec</a>.
-         */
-        double execute(char norm, int m, int n, double[] a, int lda, double[] work);
+    public static final class DlangeNode extends NativeCallNode {
 
-        static DlangeNode create() {
+        public static DlangeNode create() {
             return RFFIFactory.getLapackRFFI().createDlangeNode();
         }
-    }
 
-    interface DgeconNode extends NodeInterface {
+        private DlangeNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dlange));
+        }
+
+        public double execute(char norm, int m, int n, double[] a, int lda, double[] work) {
+            return (double) call(norm, m, n, a, lda, work);
+        }
+    }
 
-        /**
-         * See <a href="http://www.netlib.org/lapack/explore-html/db/de4/dgecon_8f.html">spec</a>.
-         */
-        int execute(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork);
+    public static final class DgeconNode extends NativeCallNode {
 
-        static DgeconNode create() {
+        public static DgeconNode create() {
             return RFFIFactory.getLapackRFFI().createDgeconNode();
         }
-    }
 
-    interface DsyevrNode extends NodeInterface {
+        private DgeconNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dgecon));
+        }
+
+        public int execute(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork) {
+            return (int) call(norm, n, a, lda, anorm, rcond, work, iwork);
+        }
+    }
 
-        int execute(char jobz, char range, char uplo, int n, double[] a, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, double[] w, double[] z, int ldz, int[] isuppz,
-                        double[] work, int lwork, int[] iwork, int liwork);
+    public static final class DsyevrNode extends NativeCallNode {
 
-        static DsyevrNode create() {
+        public static DsyevrNode create() {
             return RFFIFactory.getLapackRFFI().createDsyevrNode();
         }
-    }
 
-    interface ZunmqrNode extends NodeInterface {
+        private DsyevrNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dsyevr));
+        }
+
+        public int execute(char jobz, char range, char uplo, int n, double[] a, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, double[] w, double[] z, int ldz, int[] isuppz,
+                        double[] work, int lwork, int[] iwork, int liwork) {
+            return (int) call(jobz, range, uplo, n, a, lda, vl, vu, il, iu, abstol, m, w, z, ldz, isuppz, work, lwork, iwork, liwork);
+        }
+    }
 
-        int execute(String side, String trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork);
+    public static final class ZunmqrNode extends NativeCallNode {
 
-        static ZunmqrNode create() {
+        public static ZunmqrNode create() {
             return RFFIFactory.getLapackRFFI().createZunmqrNode();
         }
-    }
 
-    interface ZtrtrsNode extends NodeInterface {
+        private ZunmqrNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.zunmqr));
+        }
 
-        int execute(String uplo, String trans, String diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb);
+        public int execute(String side, String trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork) {
+            return (int) call(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
+        }
 
-        static ZtrtrsNode create() {
+    }
+
+    public static final class ZtrtrsNode extends NativeCallNode {
+
+        public static ZtrtrsNode create() {
             return RFFIFactory.getLapackRFFI().createZtrtrsNode();
         }
-    }
 
-    interface DtrsmNode extends NodeInterface {
+        private ZtrtrsNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.ztrtrs));
+        }
 
-        void execute(String side, String uplo, String transa, String diag, int m, int n, double alpha, double[] a, int lda, double[] b, int ldb);
+        public int execute(String uplo, String trans, String diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
+            return (int) call(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
+        }
+    }
+
+    public static final class DtrsmNode extends NativeCallNode {
 
-        static DtrsmNode create() {
+        public static DtrsmNode create() {
             return RFFIFactory.getLapackRFFI().createDtrsmNode();
         }
-    }
 
-    IlaverNode createIlaverNode();
+        private DtrsmNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dtrsm));
+        }
 
-    DgeevNode createDgeevNode();
+        public void execute(String side, String uplo, String transa, String diag, int m, int n, double alpha, double[] a, int lda, double[] b, int ldb) {
+            call(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb);
+        }
 
-    Dgeqp3Node createDgeqp3Node();
+    }
 
-    DormqrNode createDormqrNode();
+    public IlaverNode createIlaverNode() {
+        return new IlaverNode(downCallNodeFactory);
+    }
 
-    DtrtrsNode createDtrtrsNode();
+    public DgeevNode createDgeevNode() {
+        return new DgeevNode(downCallNodeFactory);
+    }
 
-    DgetrfNode createDgetrfNode();
+    public Dgeqp3Node createDgeqp3Node() {
+        return new Dgeqp3Node(downCallNodeFactory);
+    }
 
-    DpotrfNode createDpotrfNode();
+    public DormqrNode createDormqrNode() {
+        return new DormqrNode(downCallNodeFactory);
+    }
 
-    DpotriNode createDpotriNode();
+    public DtrtrsNode createDtrtrsNode() {
+        return new DtrtrsNode(downCallNodeFactory);
+    }
 
-    DpstrfNode createDpstrfNode();
+    public DgetrfNode createDgetrfNode() {
+        return new DgetrfNode(downCallNodeFactory);
+    }
 
-    DgesvNode createDgesvNode();
+    public DpotrfNode createDpotrfNode() {
+        return new DpotrfNode(downCallNodeFactory);
+    }
 
-    DgesddNode createDgesddNode();
+    public DpotriNode createDpotriNode() {
+        return new DpotriNode(downCallNodeFactory);
+    }
+
+    public DpstrfNode createDpstrfNode() {
+        return new DpstrfNode(downCallNodeFactory);
+    }
 
-    DlangeNode createDlangeNode();
+    public DgesvNode createDgesvNode() {
+        return new DgesvNode(downCallNodeFactory);
+    }
+
+    public DgesddNode createDgesddNode() {
+        return new DgesddNode(downCallNodeFactory);
+    }
 
-    DgeconNode createDgeconNode();
+    public DlangeNode createDlangeNode() {
+        return new DlangeNode(downCallNodeFactory);
+    }
 
-    DsyevrNode createDsyevrNode();
+    public DgeconNode createDgeconNode() {
+        return new DgeconNode(downCallNodeFactory);
+    }
 
-    ZunmqrNode createZunmqrNode();
+    public DsyevrNode createDsyevrNode() {
+        return new DsyevrNode(downCallNodeFactory);
+    }
 
-    ZtrtrsNode createZtrtrsNode();
+    public ZunmqrNode createZunmqrNode() {
+        return new ZunmqrNode(downCallNodeFactory);
+    }
 
-    DtrsmNode createDtrsmNode();
+    public ZtrtrsNode createZtrtrsNode() {
+        return new ZtrtrsNode(downCallNodeFactory);
+    }
 
+    public DtrsmNode createDtrsmNode() {
+        return new DtrsmNode(downCallNodeFactory);
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/MiscRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/MiscRFFI.java
index 9fb02a1e8ebb16bb3e11e874ad010d1e8ff8da6a..12d634f4f64e78d2f5841b19e9c3cc0e3e2fac77 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/MiscRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/MiscRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -22,30 +22,50 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.api.nodes.NodeInterface;
-
 /**
  * Miscellaneous methods implemented in native code.
  *
  */
-public interface MiscRFFI {
-    interface ExactSumNode extends NodeInterface {
-        double execute(double[] values, boolean hasNa, boolean naRm);
+public final class MiscRFFI {
+    private final DownCallNodeFactory downCallNodeFactory;
+
+    public MiscRFFI(DownCallNodeFactory downCallNodeFactory) {
+        this.downCallNodeFactory = downCallNodeFactory;
+    }
+
+    public static final class ExactSumNode extends NativeCallNode {
+        private ExactSumNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.exactSumFunc));
+        }
+
+        public double execute(double[] values, boolean hasNa, boolean naRm) {
+            return (double) call(values, values.length, hasNa ? 1 : 0, naRm ? 1 : 0);
+        }
 
-        static ExactSumNode create() {
+        public static ExactSumNode create() {
             return RFFIFactory.getMiscRFFI().createExactSumNode();
         }
     }
 
-    interface DqrlsNode extends NodeInterface {
-        void execute(double[] x, int n, int p, double[] y, int ny, double tol, double[] b, double[] rsd, double[] qty, int[] k, int[] jpvt, double[] qraux, double[] work);
+    public static final class DqrlsNode extends NativeCallNode {
+        private DqrlsNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.dqrls));
+        }
+
+        public void execute(double[] x, int n, int p, double[] y, int ny, double tol, double[] b, double[] rsd, double[] qty, int[] k, int[] jpvt, double[] qraux, double[] work) {
+            call(x, n, p, y, ny, tol, b, rsd, qty, k, jpvt, qraux, work);
+        }
 
-        static DqrlsNode create() {
+        public static DqrlsNode create() {
             return RFFIFactory.getMiscRFFI().createDqrlsNode();
         }
     }
 
-    ExactSumNode createExactSumNode();
+    public ExactSumNode createExactSumNode() {
+        return new ExactSumNode(downCallNodeFactory);
+    }
 
-    DqrlsNode createDqrlsNode();
+    public DqrlsNode createDqrlsNode() {
+        return new DqrlsNode(downCallNodeFactory);
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeCharArray.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallNode.java
similarity index 62%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeCharArray.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallNode.java
index cbba5538b356b1c9f3d4448752e3654e34318916..c192214100f7f8141e5ad9f325eb3c7a9ebb98b3 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeCharArray.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -20,23 +20,22 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop;
+package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.api.interop.ForeignAccess;
-import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
 
 /**
- * A {@link TruffleObject} that represents an array of {@code unsigned char} values, that is
- * {@code NULL} terminated in the C domain.
+ * Convenient base class for nodes invoking
+ * {@link com.oracle.truffle.r.runtime.ffi.DownCallNodeFactory.DownCallNode}.
  */
-public final class NativeCharArray extends NativeUInt8Array {
+public class NativeCallNode extends Node {
+    @Child private DownCallNodeFactory.DownCallNode downCallNode;
 
-    public NativeCharArray(byte[] bytes) {
-        super(bytes, true);
+    public NativeCallNode(DownCallNodeFactory.DownCallNode downCallNode) {
+        this.downCallNode = downCallNode;
     }
 
-    @Override
-    public ForeignAccess getForeignAccess() {
-        return NativeCharArrayMRForeign.ACCESS;
+    protected Object call(Object... args) {
+        return downCallNode.call(args);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
index f30a5dfbf4854a96bab0cbe6633a37fde148360f..091ab6b5132bf935b2cc5041ddb5c0735652db3d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
@@ -36,10 +36,8 @@ public enum NativeFunction {
     getpid("(): sint32", "call_base_"),
     getcwd("([uint8], sint32): sint32", "call_base_"),
     chdir("(string): sint32", "call_base_"),
-    mkdir("(string, sint32): sint32", "call_base_"),
     readlink("((string, sint32): void, string): void", "call_base_"),
     mkdtemp("([uint8]): sint32", "call_base_"),
-    chmod("(string, sint32): sint32", "call_base_"),
     strtol("((sint64, sint32): void, string, sint32): void", "call_base_"),
     uname("((string, string, string, string, string): void): void", "call_base_"),
     glob("((string): void, string): void", "call_base_"),
@@ -84,11 +82,13 @@ public enum NativeFunction {
     // FastR helpers
     set_exception_flag("(): void"),
     // FastR internal helper for R embedded mode
-    rembedded_write_console("(string, sint32):void"),
-    rembedded_write_err_console("(string, sint32):void"),
-    rembedded_read_console("(string):string"),
-    rembedded_native_clean_up("(sint32, sint32, sint32):void"),
-    rembedded_native_suicide("(string):void"),
+    rembedded_cleanup("(sint32, sint32, sint32):void", "", baseLibrary(), true),
+    rembedded_suicide("(string):void", "", baseLibrary(), true),
+    rembedded_write_console("(string, sint32):void", "", baseLibrary(), true),
+    rembedded_write_err_console("(string, sint32):void", "", baseLibrary(), true),
+    rembedded_read_console("(string):string", "", baseLibrary(), true),
+    rembedded_native_clean_up("(sint32, sint32, sint32):void", "", baseLibrary(), true),
+    rembedded_native_suicide("(string):void", "", baseLibrary(), true),
     // user-defined RNG
     unif_init("(sint32): void", "user_", anyLibrary()),
     norm_rand("(): pointer", "user_", anyLibrary()),
@@ -96,6 +96,7 @@ public enum NativeFunction {
     unif_nseed("(): pointer", "user_", anyLibrary()),
     unif_seedloc("(): pointer", "user_", anyLibrary()),
     // memory access helper functions
+    // TODO: these could use Unsafe instead
     read_pointer_int("(pointer): sint32", "caccess_"),
     read_array_int("(pointer, sint64): sint32", "caccess_"),
     read_pointer_double("(pointer): double", "caccess_"),
@@ -111,12 +112,18 @@ public enum NativeFunction {
     private final String signature;
     private final int argumentCount;
     private final String library;
+    private final boolean complexInteraction;
 
-    NativeFunction(String signature, String prefix, String library) {
+    NativeFunction(String signature, String prefix, String library, boolean complexInteraction) {
         this.callName = prefix + name();
         this.signature = signature;
         this.argumentCount = getArgCount(signature);
         this.library = library;
+        this.complexInteraction = complexInteraction;
+    }
+
+    NativeFunction(String signature, String prefix, String library) {
+        this(signature, prefix, library, false);
     }
 
     NativeFunction(String signature, String prefix) {
@@ -143,6 +150,15 @@ public enum NativeFunction {
         return library;
     }
 
+    /**
+     * Returns {@code true} if the function has complex interaction with its environment, including
+     * that it is not reentrant, uses R API (e.g. {@code allocVector}), or may invoke arbitrary user
+     * code.
+     */
+    public boolean hasComplexInteraction() {
+        return complexInteraction;
+    }
+
     // Functions because the enum constants cannot refer to static final fields:
 
     public static String anyLibrary() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/PCRERFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/PCRERFFI.java
index 90489b5ffc5ac02677c3454379bb3b45015dac57..4bc7d2fc40c411c98f1ecbfd3bdc405ed638fdeb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/PCRERFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/PCRERFFI.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
@@ -22,22 +22,41 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.api.nodes.NodeInterface;
+import java.nio.charset.StandardCharsets;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnsupportedMessageException;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray;
+import com.oracle.truffle.r.runtime.ffi.interop.pcre.CaptureNamesResult;
+import com.oracle.truffle.r.runtime.ffi.interop.pcre.CompileResult;
 
 /**
  * An interface to the <a href="http://www.pcre.org/original/doc/html/index.html">PCRE</a> library
  * for Perl regular expressions.
  */
-public interface PCRERFFI {
-    int NOTBOL = 0x00000080;
-    int CASELESS = 0x1;
+public final class PCRERFFI {
+    public static final int NOTBOL = 0x00000080;
+    public static final int CASELESS = 0x1;
+
+    private final DownCallNodeFactory downCallNodeFactory;
+
+    public PCRERFFI(DownCallNodeFactory downCallNodeFactory) {
+        this.downCallNodeFactory = downCallNodeFactory;
+    }
 
     /**
      * PCRE uses call by reference for error-related information, which we encapsulate and sanitize
      * in this class. The {@code result} value (which is typically an opaque pointer to an internal
      * C struct), is the actual result of the function as per the PCRE spec.
      */
-    class Result {
+    public static final class Result {
         public final long result;
         public final String errorMessage;
         public final int errOffset;
@@ -49,64 +68,142 @@ public interface PCRERFFI {
         }
     }
 
-    interface MaketablesNode extends NodeInterface {
-        long execute();
+    public static final class MaketablesNode extends NativeCallNode {
+        @Child private Node asPointerNode;
+
+        private MaketablesNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.maketables));
+        }
+
+        public long execute() {
+            Object result = call();
+            if (result instanceof Long) {
+                return (long) result;
+            }
+            assert result instanceof TruffleObject;
+            if (asPointerNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                asPointerNode = insert(Message.AS_POINTER.createNode());
+            }
+            try {
+                return ForeignAccess.sendAsPointer(asPointerNode, (TruffleObject) result);
+            } catch (UnsupportedMessageException e) {
+                throw RInternalError.shouldNotReachHere("PCRE function maketables should return long or TruffleObject that represents a pointer.");
+            }
+        }
 
-        static MaketablesNode create() {
+        public static MaketablesNode create() {
             return RFFIFactory.getPCRERFFI().createMaketablesNode();
         }
     }
 
-    interface CompileNode extends NodeInterface {
-        Result execute(String pattern, int options, long tables);
+    public static final class CompileNode extends NativeCallNode {
+        private CompileNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.compile));
+        }
+
+        public Result execute(String pattern, int options, long tables) {
+            CompileResult data = new CompileResult();
+            call(data, pattern, options, tables);
+            return data.getResult();
+        }
 
-        static CompileNode create() {
+        public static CompileNode create() {
             return RFFIFactory.getPCRERFFI().createCompileNode();
         }
     }
 
-    interface GetCaptureCountNode extends NodeInterface {
-        int execute(long code, long extra);
+    public static final class GetCaptureCountNode extends NativeCallNode {
+        private GetCaptureCountNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.getcapturecount));
+        }
+
+        public int execute(long code, long extra) {
+            return (int) call(code, extra);
+        }
 
-        static GetCaptureCountNode create() {
+        public static GetCaptureCountNode create() {
             return RFFIFactory.getPCRERFFI().createGetCaptureCountNode();
         }
     }
 
-    interface GetCaptureNamesNode extends NodeInterface {
-        String[] execute(long code, long extra, int captureCount);
+    public static final class GetCaptureNamesNode extends NativeCallNode {
+        private GetCaptureNamesNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.getcapturenames));
+        }
+
+        public String[] execute(long code, long extra, int captureCount) {
+            CaptureNamesResult data = new CaptureNamesResult(captureCount);
+            int result = (int) call(data, code, extra);
+            if (result < 0) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(RError.NO_CALLER, RError.Message.WRONG_PCRE_INFO, result);
+            } else {
+                return data.getCaptureNames();
+            }
+        }
 
-        static GetCaptureNamesNode create() {
+        public static GetCaptureNamesNode create() {
             return RFFIFactory.getPCRERFFI().createGetCaptureNamesNode();
         }
     }
 
-    interface StudyNode extends NodeInterface {
-        Result execute(long code, int options);
+    public static final class StudyNode extends NativeCallNode {
+        private StudyNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.study));
+        }
+
+        public Result execute(long code, int options) {
+            throw RInternalError.shouldNotReachHere("The factory method should throw unimplemented already");
+        }
 
-        static StudyNode create() {
+        public static StudyNode create() {
             return RFFIFactory.getPCRERFFI().createStudyNode();
         }
     }
 
-    interface ExecNode extends NodeInterface {
-        int execute(long code, long extra, String subject, int offset, int options, int[] ovector);
+    public static final class ExecNode extends NativeCallNode {
+        private ExecNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.exec));
+        }
+
+        public int execute(long code, long extra, String subject, int offset, int options, int[] ovector) {
+            byte[] subjectBytes = getBytes(subject);
+            NativeCharArray subjectChars = new NativeCharArray(subjectBytes);
+            return (int) call(code, extra, subjectChars, subjectBytes.length, offset, options, ovector, ovector.length);
+        }
+
+        @TruffleBoundary
+        private static byte[] getBytes(String subject) {
+            return subject.getBytes(StandardCharsets.UTF_8);
+        }
 
-        static ExecNode create() {
+        public static ExecNode create() {
             return RFFIFactory.getPCRERFFI().createExecNode();
         }
     }
 
-    MaketablesNode createMaketablesNode();
-
-    CompileNode createCompileNode();
+    public MaketablesNode createMaketablesNode() {
+        return new MaketablesNode(downCallNodeFactory);
+    }
 
-    GetCaptureCountNode createGetCaptureCountNode();
+    public CompileNode createCompileNode() {
+        return new CompileNode(downCallNodeFactory);
+    }
 
-    GetCaptureNamesNode createGetCaptureNamesNode();
+    public GetCaptureCountNode createGetCaptureCountNode() {
+        return new GetCaptureCountNode(downCallNodeFactory);
+    }
 
-    StudyNode createStudyNode();
+    public GetCaptureNamesNode createGetCaptureNamesNode() {
+        return new GetCaptureNamesNode(downCallNodeFactory);
+    }
 
-    ExecNode createExecNode();
+    public StudyNode createStudyNode() {
+        throw RInternalError.unimplemented("study function in PCRE");
+    }
 
+    public ExecNode createExecNode() {
+        return new ExecNode(downCallNodeFactory);
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/REmbedRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/REmbedRFFI.java
index 929f2558b46f0d5de02413c1f7c6c30f4e75ef66..52a059a1558a5553aeeb015339b7a1bbc4a8d673 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/REmbedRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/REmbedRFFI.java
@@ -22,40 +22,131 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.api.nodes.NodeInterface;
+import com.oracle.truffle.api.CompilerDirectives;
+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.ffi.DownCallNodeFactory.DownCallNode;
 
 /**
  * Function down-calls related to the embedded API. TODO: these all should be invoked as proper
  * down-calls because the user code may want to use R API.
  */
-public interface REmbedRFFI {
-    interface ReadConsoleNode extends NodeInterface {
-        String execute(String prompt);
+public final class REmbedRFFI {
+    private final DownCallNodeFactory downCallNodeFactory;
 
-        static REmbedRFFI.ReadConsoleNode create() {
+    public REmbedRFFI(DownCallNodeFactory downCallNodeFactory) {
+        this.downCallNodeFactory = downCallNodeFactory;
+    }
+
+    public static final class ReadConsoleNode extends NativeCallNode {
+        @Child private Node unboxNode;
+
+        private ReadConsoleNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.rembedded_read_console));
+        }
+
+        public String execute(String prompt) {
+            Object result = call(prompt);
+            if (result instanceof String) {
+                return (String) result;
+            }
+            assert result instanceof TruffleObject : "NFI is expected to send us TruffleObject or String";
+            if (unboxNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                unboxNode = insert(Message.UNBOX.createNode());
+            }
+            try {
+                return (String) ForeignAccess.sendUnbox(unboxNode, (TruffleObject) result);
+            } catch (ClassCastException | UnsupportedMessageException e) {
+                CompilerDirectives.transferToInterpreter();
+                throw RInternalError.shouldNotReachHere("Unboxing TruffleObject from NFI, which should be String wrapper, failed. " + e.getMessage());
+            }
+        }
+
+        public static REmbedRFFI.ReadConsoleNode create() {
             return RFFIFactory.getREmbedRFFI().createReadConsoleNode();
         }
     }
 
-    interface WriteConsoleBaseNode extends NodeInterface {
-        void execute(String x);
+    public abstract static class WriteConsoleBaseNode extends NativeCallNode {
+        private WriteConsoleBaseNode(DownCallNode downCallNode) {
+            super(downCallNode);
+        }
+
+        public final void execute(String x) {
+            call(x, x.length());
+        }
     }
 
-    interface WriteConsoleNode extends WriteConsoleBaseNode {
-        static REmbedRFFI.WriteConsoleNode create() {
+    public static final class WriteConsoleNode extends WriteConsoleBaseNode {
+        public static REmbedRFFI.WriteConsoleNode create() {
             return RFFIFactory.getREmbedRFFI().createWriteConsoleNode();
         }
+
+        public WriteConsoleNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.rembedded_write_console));
+        }
     }
 
-    interface WriteErrConsoleNode extends WriteConsoleBaseNode {
-        static REmbedRFFI.WriteErrConsoleNode create() {
+    public static final class WriteErrConsoleNode extends WriteConsoleBaseNode {
+        public static REmbedRFFI.WriteErrConsoleNode create() {
             return RFFIFactory.getREmbedRFFI().createWriteErrConsoleNode();
         }
+
+        public WriteErrConsoleNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.rembedded_write_err_console));
+        }
     }
 
-    ReadConsoleNode createReadConsoleNode();
+    public static final class EmbeddedSuicideNode extends NativeCallNode {
+        private EmbeddedSuicideNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.rembedded_suicide));
+        }
 
-    WriteConsoleNode createWriteConsoleNode();
+        public void execute(String message) {
+            call(message);
+        }
 
-    WriteErrConsoleNode createWriteErrConsoleNode();
+        public static EmbeddedSuicideNode create() {
+            return RFFIFactory.getREmbedRFFI().createEmbeddedSuicideNode();
+        }
+    }
+
+    public static final class EmbeddedCleanUpNode extends NativeCallNode {
+        private EmbeddedCleanUpNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.rembedded_cleanup));
+        }
+
+        public void execute(int x, int y, int z) {
+            call(x, y, z);
+        }
+
+        public static EmbeddedCleanUpNode create() {
+            return RFFIFactory.getREmbedRFFI().createEmbeddedCleanUpNode();
+        }
+    }
+
+    ReadConsoleNode createReadConsoleNode() {
+        return new ReadConsoleNode(downCallNodeFactory);
+    }
+
+    WriteConsoleNode createWriteConsoleNode() {
+        return new WriteConsoleNode(downCallNodeFactory);
+    }
+
+    WriteErrConsoleNode createWriteErrConsoleNode() {
+        return new WriteErrConsoleNode(downCallNodeFactory);
+    }
+
+    public EmbeddedSuicideNode createEmbeddedSuicideNode() {
+        return new EmbeddedSuicideNode(downCallNodeFactory);
+    }
+
+    public EmbeddedCleanUpNode createEmbeddedCleanUpNode() {
+        return new EmbeddedCleanUpNode(downCallNodeFactory);
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StatsRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StatsRFFI.java
index 5fcbb0417f429677b0e2d52588462c62b953a8db..7bb4b22dbf286d135040a4dc1d80623091f91668 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StatsRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StatsRFFI.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
@@ -22,41 +22,69 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.api.nodes.NodeInterface;
-
 /**
  * Interface to native (C) methods provided by the {@code stats} package that are used to implement
- * {@code.Call(C_fft)}. The implementation is split into a Java part which calls the
+ * {@code .Call(C_fft)}. The implementation is split into a Java part which calls the
  * {@code fft_factor} and {@code fft_work}. functions from the GNU R C code.
  */
-public interface StatsRFFI {
-    interface FactorNode extends NodeInterface {
-        void execute(int n, int[] pmaxf, int[] pmaxp);
+public final class StatsRFFI {
+    private final DownCallNodeFactory downCallNodeFactory;
+
+    public StatsRFFI(DownCallNodeFactory downCallNodeFactory) {
+        this.downCallNodeFactory = downCallNodeFactory;
+    }
+
+    public static final class FactorNode extends NativeCallNode {
+        private FactorNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.fft_factor));
+        }
+
+        public void execute(int n, int[] pmaxf, int[] pmaxp) {
+            call(n, pmaxf, pmaxp);
+        }
 
-        static FactorNode create() {
+        public static FactorNode create() {
             return RFFIFactory.getStatsRFFI().createFactorNode();
         }
     }
 
-    interface WorkNode extends NodeInterface {
-        int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork);
+    public static final class WorkNode extends NativeCallNode {
+        private WorkNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.fft_work));
+        }
+
+        public int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
+            return (int) call(a, nseg, n, nspn, isn, work, iwork);
+        }
 
-        static WorkNode create() {
+        public static WorkNode create() {
             return RFFIFactory.getStatsRFFI().createWorkNode();
         }
     }
 
-    interface LminflNode extends NodeInterface {
-        void execute(double[] x, int ldx, int n, int k, int docoef, double[] qraux, double[] resid, double[] hat, double[] coef, double[] sigma, double tol);
+    public static final class LminflNode extends NativeCallNode {
+        private LminflNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.lminfl));
+        }
+
+        public void execute(double[] x, int ldx, int n, int k, int docoef, double[] qraux, double[] resid, double[] hat, double[] coef, double[] sigma, double tol) {
+            call(x, ldx, n, k, docoef, qraux, resid, hat, coef, sigma, tol);
+        }
 
-        static LminflNode create() {
+        public static LminflNode create() {
             return RFFIFactory.getStatsRFFI().createLminflNode();
         }
     }
 
-    FactorNode createFactorNode();
+    public FactorNode createFactorNode() {
+        return new FactorNode(downCallNodeFactory);
+    }
 
-    WorkNode createWorkNode();
+    public WorkNode createWorkNode() {
+        return new WorkNode(downCallNodeFactory);
+    }
 
-    LminflNode createLminflNode();
+    public LminflNode createLminflNode() {
+        return new LminflNode(downCallNodeFactory);
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ToolsRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ToolsRFFI.java
index 629bc1a5889deaf3bfc9beaa9784423f32ae5e16..34ef4a966a9d902205ce7a03b932b5fe1b5d8b69 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ToolsRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ToolsRFFI.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
@@ -22,17 +22,30 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeInterface;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.conn.RConnection;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
 /**
  * Interface to native (C) methods provided by the {@code tools} package.
  */
-public interface ToolsRFFI {
-    interface ParseRdNode extends NodeInterface {
+public final class ToolsRFFI {
+    public static class ParseRdNode extends Node {
+        private static final String C_PARSE_RD = "C_parseRd";
+        protected static final String TOOLS = "tools";
+
+        @Child private CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getCallRFFI().createInvokeCallNode();
+        @Child private DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
+
+        @CompilationFinal private NativeCallInfo nativeCallInfo;
+
         /**
          * This invokes the Rd parser, written in C, and part of GnuR, that does its work using the
          * R FFI interface. The R code initially invokes this via {@code .External2(C_parseRd, ...)}
@@ -41,9 +54,28 @@ public interface ToolsRFFI {
          * code. We can't go straight to the GnuR C entry point as that makes GnuR-specific
          * assumptions about, for example, how connections are implemented.
          */
-        Object execute(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
-                        RLogicalVector warndups);
+        public Object execute(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
+                        RLogicalVector warndups) {
+            synchronized (ToolsRFFI.class) {
+                try {
+                    if (nativeCallInfo == null) {
+                        // lookup entry point (assert library is loaded)
+                        DLLInfo toolsDLLInfo = DLL.findLibrary(TOOLS);
+                        assert toolsDLLInfo != null;
+                        SymbolHandle symbolHandle = findSymbolNode.execute(C_PARSE_RD, TOOLS, DLL.RegisteredNativeSymbol.any());
+                        assert symbolHandle != DLL.SYMBOL_NOT_FOUND;
+                        nativeCallInfo = new NativeCallInfo(C_PARSE_RD, symbolHandle, toolsDLLInfo);
+                    }
+                    return callRFFINode.dispatch(nativeCallInfo,
+                                    new Object[]{con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups});
+                } catch (Throwable ex) {
+                    throw RInternalError.shouldNotReachHere(ex, "error during Rd parsing" + ex.getMessage());
+                }
+            }
+        }
     }
 
-    ParseRdNode createParseRdNode();
+    public ParseRdNode createParseRdNode() {
+        return new ParseRdNode();
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java
index b02f3fefda00323895da30c32733c2394f1ed0fe..122b0af2d475c5fbceaca8975fca7360d0fc929c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java
@@ -24,43 +24,77 @@ package com.oracle.truffle.r.runtime.ffi;
 
 import com.oracle.truffle.api.CallTarget;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.NodeInterface;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.ffi.interop.NativeRawArray;
 
 /**
  * zip compression/uncompression.
  */
-public interface ZipRFFI {
+public final class ZipRFFI {
+
+    private final DownCallNodeFactory downCallNodeFactory;
+
+    public ZipRFFI(DownCallNodeFactory downCallNodeFactory) {
+        this.downCallNodeFactory = downCallNodeFactory;
+    }
+
+    public static final class CompressNode extends NativeCallNode {
+        private CompressNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.compress));
+        }
 
-    interface CompressNode extends NodeInterface {
         /**
          * compress {@code source} into {@code dest}.
          *
          * @return standard return code (0 ok)
          */
-        int execute(byte[] dest, byte[] source);
+        public int execute(byte[] dest, byte[] source) {
+            NativeRawArray nativeDest = new NativeRawArray(dest);
+            NativeRawArray nativeSource = new NativeRawArray(source);
+            try {
+                return (int) call(nativeDest, dest.length, nativeSource, source.length);
+            } finally {
+                nativeDest.getValue();
+            }
+        }
 
-        static CompressNode create() {
+        public static CompressNode create() {
             return RFFIFactory.getZipRFFI().createCompressNode();
         }
     }
 
-    interface UncompressNode extends NodeInterface {
+    public static final class UncompressNode extends NativeCallNode {
+        private UncompressNode(DownCallNodeFactory factory) {
+            super(factory.createDownCallNode(NativeFunction.uncompress));
+        }
+
         /**
          * uncompress {@code source} into {@code dest}.
          *
          * @return standard return code (0 ok)
          */
-        int execute(byte[] dest, byte[] source);
+        public int execute(byte[] dest, byte[] source) {
+            NativeRawArray nativeDest = new NativeRawArray(dest);
+            NativeRawArray nativeSource = new NativeRawArray(source);
+            try {
+                return (int) call(nativeDest, dest.length, nativeSource, source.length);
+            } finally {
+                nativeDest.getValue();
+            }
+        }
     }
 
-    CompressNode createCompressNode();
+    public CompressNode createCompressNode() {
+        return new CompressNode(downCallNodeFactory);
+    }
 
-    UncompressNode createUncompressNode();
+    public UncompressNode createUncompressNode() {
+        return new UncompressNode(downCallNodeFactory);
+    }
 
     // RootNodes for calling when not in Truffle context
 
-    final class CompressRootNode extends RFFIRootNode<CompressNode> {
+    public static final class CompressRootNode extends RFFIRootNode<CompressNode> {
         protected CompressRootNode(CompressNode wrapped) {
             super(wrapped);
         }
@@ -76,7 +110,7 @@ public interface ZipRFFI {
         }
     }
 
-    final class UncompressRootNode extends RFFIRootNode<UncompressNode> {
+    public static final class UncompressRootNode extends RFFIRootNode<UncompressNode> {
         protected UncompressRootNode(UncompressNode wrapped) {
             super(wrapped);
         }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ESoftVersionResult.java
similarity index 96%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ESoftVersionResult.java
index a3e8e86c2f81530097ea840db51d5df9eb2b62fe..c4416b12ec5180dc8708aec4f1bf95702306e205 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ESoftVersionResult.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ESoftVersionResultMR.java
similarity index 97%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ESoftVersionResultMR.java
index fc958b7b30ff2f235e3ff12999bb024c86b95d03..6eab2ce42bf835d0243924128675a6968e318a17 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ESoftVersionResultMR.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/GlobResult.java
similarity index 92%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResult.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/GlobResult.java
index f16e91a2fd014471506fee031d659465fddc5608..13bbc84cdd403559187bff7e225147e2339e4e6c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResult.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/GlobResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import java.util.ArrayList;
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResultMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/GlobResultMR.java
similarity index 94%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResultMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/GlobResultMR.java
index 2c7d26e85ebb434f93a49538445f719cba5a7375..1aaf118a5287670f12e1860b28c3a408684ab016 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResultMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/GlobResultMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ReadlinkResult.java
similarity index 92%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResult.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ReadlinkResult.java
index 266efc5acd98170a936c2be67035fd96826d5183..3466cf3bb0e759f7c740748741b970c1e06b8dc0 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResult.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ReadlinkResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResultMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ReadlinkResultMR.java
similarity index 98%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResultMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ReadlinkResultMR.java
index c17152410ed4da5918bf3224085f47774076a21e..98e1f175a90e5fca475665fb9814437725f7f2cf 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResultMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/ReadlinkResultMR.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.ForeignAccess;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/StrtolResult.java
similarity index 92%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResult.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/StrtolResult.java
index 1884ad0bfabd6141941fe6c87e211e476a2bb673..4585fa57f17e5135dee4277a60325b3129b9c0d5 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResult.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/StrtolResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResultMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/StrtolResultMR.java
similarity index 94%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResultMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/StrtolResultMR.java
index 0b306587388575e332cb810dcfcb9bb583ae2f19..be8acf978ed2bde78fd1cb60911c4960cc07a567 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResultMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/StrtolResultMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/UnameResult.java
similarity index 88%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResult.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/UnameResult.java
index 097610794db07e03b3776ce21e35dade8c0e7d60..ef8c8e5ce50c31144806857d3abbcb9d812bbefe 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResult.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/UnameResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,13 +20,13 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
-import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI.UtsName;
 
-public final class UnameResult implements BaseRFFI.UtsName, RTruffleObject {
+public final class UnameResult implements UtsName, RTruffleObject {
     private String sysname;
     private String release;
     private String version;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResultMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/UnameResultMR.java
similarity index 94%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResultMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/UnameResultMR.java
index e63607fbadda495659e53bb855afef2f44343882..bf9a16a1aceb6515aa58fb0f9e46c1e0979f630c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResultMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/base/UnameResultMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.base;
+package com.oracle.truffle.r.runtime.ffi.base;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArray.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArray.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf414ccbd0164fea7831a2bd7e7c38b8feb1f3e6
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArray.java
@@ -0,0 +1,80 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi.interop;
+
+import java.nio.charset.StandardCharsets;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.TruffleObject;
+
+/**
+ * A {@link TruffleObject} that represents an array of {@code unsigned char} values, that is
+ * {@code NULL} terminated in the C domain.
+ */
+public final class NativeCharArray extends NativeUInt8Array {
+
+    public NativeCharArray(byte[] bytes) {
+        super(bytes, true);
+    }
+
+    @TruffleBoundary
+    public NativeCharArray(String value) {
+        super(value.getBytes(StandardCharsets.UTF_8), true);
+    }
+
+    private NativeCharArray(byte[] bytes, boolean nullTerminate) {
+        super(bytes, nullTerminate);
+    }
+
+    /**
+     * Creates {@link NativeCharArray} of given length that can be used for output parameters, it is
+     * not null terminated.
+     */
+    public static NativeCharArray crateOutputBuffer(int length) {
+        return new NativeCharArray(new byte[length], false);
+    }
+
+    /**
+     * Finds the null terminator and creates the Java String accordingly.
+     */
+    public String getStringFromOutputBuffer() {
+        assert !fakesNullTermination() : "create the buffer string via createOutputBuffer()";
+        byte[] mbuf = getValue();
+        int i = 0;
+        while (mbuf[i] != 0 && i < mbuf.length) {
+            i++;
+        }
+        return new String(mbuf, 0, i);
+    }
+
+    public String getString() {
+        byte[] val = getValue();
+        return new String(val, 0, fakesNullTermination() ? val.length : val.length - 1);
+    }
+
+    @Override
+    public ForeignAccess getForeignAccess() {
+        return NativeCharArrayMRForeign.ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeCharArrayMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArrayMR.java
similarity index 98%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeCharArrayMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArrayMR.java
index ed1b0f2f724a39dae220fef5fe7dee7aae049e87..f52dd8e2e15a2b90da13f3c84f66b2de3814e5e4 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeCharArrayMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeCharArrayMR.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop;
+package com.oracle.truffle.r.runtime.ffi.interop;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativePointer.java
similarity index 87%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointer.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativePointer.java
index 4202b55d79b54e8f96eaf3149a1a7ddfe2b296f7..a42e1133dc9f28558d8e186774bf7c0e3586fdc1 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointer.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativePointer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -20,12 +20,11 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop;
+package com.oracle.truffle.r.runtime.ffi.interop;
 
 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.r.ffi.impl.llvm.TruffleLLVM_Utils;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 
@@ -79,16 +78,6 @@ public class NativePointer implements TruffleObject {
         return obj instanceof NativePointer;
     }
 
-    public static TruffleObject check(TruffleObject object) {
-        long nativePointer = TruffleLLVM_Utils.getNativeAddress(object);
-        for (int i = tableHwm - 1; i >= 0; i--) {
-            if (table[i].nativePointer == nativePointer) {
-                return table[i].object;
-            }
-        }
-        return null;
-    }
-
     final long asPointer() {
         long result = asPointerImpl();
         boolean newPointer = true;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointerMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativePointerMR.java
similarity index 93%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointerMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativePointerMR.java
index b8b73f6378c2b02ff692b92b425fa8d69a5526d4..604aef2eb8ece9561c3c7d227574c43b9c49c00c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointerMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativePointerMR.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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop;
+package com.oracle.truffle.r.runtime.ffi.interop;
 
 import com.oracle.truffle.api.interop.MessageResolution;
 import com.oracle.truffle.api.interop.Resolve;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeRawArray.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeRawArray.java
similarity index 91%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeRawArray.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeRawArray.java
index 631188e69b63a5c702720eadfad09fff01772e19..7194fccdbfa6abec4d74072e6a2a41d4cd3f94e0 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeRawArray.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeRawArray.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop;
+package com.oracle.truffle.r.runtime.ffi.interop;
 
 import com.oracle.truffle.api.interop.ForeignAccess;
 
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeRawArrayMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeRawArrayMR.java
similarity index 96%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeRawArrayMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeRawArrayMR.java
index a17becc8ed2f2a4433bccc8b11b32517df567f2f..21d367ac68ef86d580f089f60c8d168cfbf98a90 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeRawArrayMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeRawArrayMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop;
+package com.oracle.truffle.r.runtime.ffi.interop;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeUInt8Array.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeUInt8Array.java
similarity index 77%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeUInt8Array.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeUInt8Array.java
index 4bf73b78c4c4c7517fd31ffb4dd4c53f95beed58..033d78e53b96f2ee582c71c3147a368d23ccb9fe 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativeUInt8Array.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/NativeUInt8Array.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -20,11 +20,10 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop;
+package com.oracle.truffle.r.runtime.ffi.interop;
 
-import static com.oracle.truffle.r.ffi.impl.interop.UnsafeAdapter.UNSAFE;
+import static com.oracle.truffle.r.runtime.ffi.UnsafeAdapter.UNSAFE;
 
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 
@@ -38,26 +37,26 @@ import sun.misc.Unsafe;
  * N.B. Java never stores a {@code NULL} value in a String or the byte array from
  * {@link String#getBytes}.
  *
- * If {@link #fakeNull()} is {@code true}, then {@link #read} returns 0, else it is an error;
- * similar for {@link #write}.
+ * If {@link #fakesNullTermination()} is {@code true}, then {@link #read} returns 0, else it is an
+ * error; similar for {@link #write}.
  */
 public abstract class NativeUInt8Array implements RTruffleObject {
 
-    public final byte[] bytes;
+    public byte[] bytes;
 
     /**
      * If the array escapes the Truffle world via {@link #convertToNative()}, this value will be
      * non-zero and is used exclusively thereafter.
      */
-    @CompilationFinal protected long nativeAddress;
-    private final int effectiveLength;
+    protected long nativeAddress;
+    private int effectiveLength;
 
     protected NativeUInt8Array(byte[] bytes, boolean nullTerminate) {
         this.bytes = bytes;
         this.effectiveLength = bytes.length + (nullTerminate ? 1 : 0);
     }
 
-    private boolean fakeNull() {
+    public boolean fakesNullTermination() {
         return bytes.length != effectiveLength;
     }
 
@@ -72,7 +71,7 @@ public abstract class NativeUInt8Array implements RTruffleObject {
             checkNativeIndex(index);
             UNSAFE.putByte(nativeAddress + index, value);
         } else {
-            if (index == bytes.length && fakeNull()) {
+            if (index == bytes.length && fakesNullTermination()) {
                 // ignore
             } else {
                 bytes[index] = value;
@@ -85,7 +84,7 @@ public abstract class NativeUInt8Array implements RTruffleObject {
             checkNativeIndex(index);
             return UNSAFE.getByte(nativeAddress + index);
         } else {
-            if (index == bytes.length && fakeNull()) {
+            if (index == bytes.length && fakesNullTermination()) {
                 return (byte) 0;
             }
             return bytes[index];
@@ -107,21 +106,26 @@ public abstract class NativeUInt8Array implements RTruffleObject {
     private void allocateNative() {
         nativeAddress = UNSAFE.allocateMemory(effectiveLength);
         UNSAFE.copyMemory(bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, nativeAddress, bytes.length);
-        if (fakeNull()) {
+        if (fakesNullTermination()) {
             UNSAFE.putByte(nativeAddress + bytes.length, (byte) 0);
         }
     }
 
     public byte[] getValue() {
         if (nativeAddress != 0) {
-            copyBackFromNative();
+            copyBackFromNative(bytes);
         }
         return bytes;
     }
 
+    public void setValue(byte[] newBytes, boolean isNullTerminated) {
+        bytes = newBytes;
+        effectiveLength = isNullTerminated ? bytes.length + 1 : bytes.length;
+    }
+
     @TruffleBoundary
-    private void copyBackFromNative() {
+    private void copyBackFromNative(byte[] target) {
         // copy back
-        UNSAFE.copyMemory(null, nativeAddress, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, bytes.length);
+        UNSAFE.copyMemory(null, nativeAddress, target, Unsafe.ARRAY_BYTE_BASE_OFFSET, bytes.length);
     }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CaptureNamesResult.java
similarity index 92%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResult.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CaptureNamesResult.java
index e54b5787ad7be62e23ff9d5f422a873cd5df595c..3e8ab84265cc3599f8fd1777755aecbe5e2367ec 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResult.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CaptureNamesResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.pcre;
+package com.oracle.truffle.r.runtime.ffi.interop.pcre;
 
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResultMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CaptureNamesResultMR.java
similarity index 95%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResultMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CaptureNamesResultMR.java
index b836331256e6177b658fbdfa449e6df65398e4aa..32f06e731380f335f03aabe220dddca1fe618258 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResultMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CaptureNamesResultMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.pcre;
+package com.oracle.truffle.r.runtime.ffi.interop.pcre;
 
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.ForeignAccess;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CompileResult.java
similarity index 85%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResult.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CompileResult.java
index 946d2a8b8d27cd7cd0b8ec6f60938c3828c95060..fb3fb04f813456ab0597f2e4b94f247bc3707435 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResult.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CompileResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,17 +20,18 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.pcre;
+package com.oracle.truffle.r.runtime.ffi.interop.pcre;
 
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
+import com.oracle.truffle.r.runtime.ffi.PCRERFFI.Result;
 
 public final class CompileResult implements RTruffleObject {
     private PCRERFFI.Result result;
 
     public void set(long pcreResult, String errorMessage, int errOffset) {
-        result = new PCRERFFI.Result(pcreResult, errorMessage, errOffset);
+        result = new Result(pcreResult, errorMessage, errOffset);
     }
 
     public PCRERFFI.Result getResult() {
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResultMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CompileResultMR.java
similarity index 96%
rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResultMR.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CompileResultMR.java
index 76562a7e33a500bff2fe2568dcf7431996048011..e6ecb9e2f8da05b14fb92ccd674cacb34e1171d0 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResultMR.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/interop/pcre/CompileResultMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.ffi.impl.interop.pcre;
+package com.oracle.truffle.r.runtime.ffi.interop.pcre;
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.CanResolve;