diff --git a/.gitignore b/.gitignore
index 756f43343ccdae38768bd7d156b05bbf8109fabc..431b9e0bcedb9a1c51376555882b0f4da06fb54d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,7 +73,7 @@
 *.dot
 *.pyc
 *.hprof
-\javafilelist.txt
+javafilelist.txt
 .hprof.txt
 /compilations-*.cfg
 /graal/.*/build.xml
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
index cc2f268bcf1070ea534f29baa37af3f52b3fddb8..161c25219a125d9b88ffdf8373e9b68867f40466 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
@@ -33,6 +33,7 @@ import java.util.List;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.RootCallTarget;
+import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.nodes.Node;
@@ -719,4 +720,10 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
     public void checkDebugRequest(RFunction func) {
         RInstrumentation.checkDebugRequested(func);
     }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public Class<? extends TruffleLanguage> getTruffleRLanguage() {
+        return TruffleRLanguage.class;
+    }
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/DLLDotSymbolMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/DLLDotSymbolMR.java
new file mode 100644
index 0000000000000000000000000000000000000000..3342f4a737ae56c2d35cc346a46e3d94a7565624
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/DLLDotSymbolMR.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.interop;
+
+import com.oracle.truffle.api.interop.CanResolve;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.engine.TruffleRLanguage;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+
+@MessageResolution(receiverType = DLL.DotSymbol.class, language = TruffleRLanguage.class)
+public class DLLDotSymbolMR {
+    @CanResolve
+    public abstract static class DotSymbolCheck extends Node {
+
+        protected static boolean test(TruffleObject receiver) {
+            return receiver instanceof DLL.DotSymbol;
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/DLLInfoMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/DLLInfoMR.java
new file mode 100644
index 0000000000000000000000000000000000000000..92a4118c055bfe7c4c27ff88caf52213eb8e25ba
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/DLLInfoMR.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.interop;
+
+import com.oracle.truffle.api.interop.CanResolve;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.engine.TruffleRLanguage;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+
+@MessageResolution(receiverType = DLL.DLLInfo.class, language = TruffleRLanguage.class)
+public class DLLInfoMR {
+    @CanResolve
+    public abstract static class DLLInfolCheck extends Node {
+
+        protected static boolean test(TruffleObject receiver) {
+            return receiver instanceof DLL.DLLInfo;
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RExternalPtrMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RExternalPtrMR.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d21bccdf2f6a6d0a2b6dece2a5b38aa99b09598
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RExternalPtrMR.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.interop;
+
+import com.oracle.truffle.api.interop.CanResolve;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.engine.TruffleRLanguage;
+import com.oracle.truffle.r.runtime.data.RExternalPtr;
+
+@MessageResolution(receiverType = RExternalPtr.class, language = TruffleRLanguage.class)
+public class RExternalPtrMR {
+    @CanResolve
+    public abstract static class RExternalPtrCheck extends Node {
+
+        protected static boolean test(TruffleObject receiver) {
+            return receiver instanceof RExternalPtr;
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java
index 03f73455c63146019f8c9bb5a4ffdfead920049b..4e2a81101dde3a94799a5219af80a090d17c33e3 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java
@@ -22,88 +22,250 @@
  */
 package com.oracle.truffle.r.engine.interop;
 
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.Assumption;
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.r.engine.TruffleRLanguage;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RForeignAccessFactory;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RComplexVector;
+import com.oracle.truffle.r.runtime.data.RDoubleSequence;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RIntSequence;
+import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.data.RRawVector;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
+import com.oracle.truffle.r.runtime.data.RUnboundValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
+import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
 
+/**
+ * A {@link ForeignAccess} instance captures the {@link Thread} that creates it and all uses are
+ * checked against the current thread. Therefore, in a world with multiple {@link PolyglotEngine}s,
+ * aka multiple {@link Thread} and {@link RContext} instances, it is not possible to use a simple
+ * global constant value for the {@link ForeignAccess} instance that could be associated directly
+ * with the {@link TruffleObject} class.
+ *
+ * This factory provides a generic solution for all FastR types (all of which are
+ * {@link TruffleObject}s), at some cost in performance.
+ *
+ * The REALLY bad news is that we cannot use {@link RContext} to store the state because, although
+ * that should be possible, at the time the call to {@link #getForeignAccess(RTruffleObject)}
+ * happens the {@link RContext} may not have been associated with a thread, so
+ * {@link RContext#getInstance()} will fail. In short the mapping has to be established using
+ * {@link Thread} not {@link RContext} and there is no call that informs us ahead of a call to
+ * {@link #getForeignAccess} that a new thread is in play. We use a Truffle {@link Assumption} to
+ * provide a fast path in the normal, single-threaded, case. TODO Apparently a call to
+ * {@link #getForeignAccess(RTruffleObject)} should,in fact, only occur on the slow path, and an
+ * assertion to that effect has been added. If true, then the fast path code can be simplified.
+ *
+ * For most types we use the {@link MessageResolution} facility to automatically generate the
+ * factory for creating the {@link ForeignAccess} instance. The exceptions are the (many) subclasses
+ * of {@link RAbstractVector} as these have the same handling but the generator cannot handle
+ * abstract classes.
+ *
+ */
 public final class RForeignAccessFactoryImpl implements RForeignAccessFactory {
+    /**
+     * The subset of the full set of types that are supported for foreign access. N.B. This list
+     * includes types that are not expected to travel between high-level languages, but may travel
+     * into the native world (when implemented in Truffle).
+     */
+    private static final Class<?>[] FOREIGN_CLASSES = new Class<?>[]{
+                    RRaw.class, RComplex.class, RIntSequence.class,
+                    RDoubleSequence.class, RIntVector.class, RDoubleVector.class,
+                    RRawVector.class, RComplexVector.class, RStringVector.class, RLogicalVector.class,
+                    RFunction.class, RNull.class, REnvironment.class,
+                    RList.class, RSymbol.class,
+                    RPairList.class, RExternalPtr.class, RUnboundValue.class,
+                    DLLInfo.class, DotSymbol.class};
+
+    private static final class ForeignAccessState {
+
+        private static final class TableEntry {
+            private final Class<? extends RTruffleObject> clazz; // for sanity check
+            private final ForeignAccess foreignAccess;
+
+            private TableEntry(Class<? extends RTruffleObject> clazz, ForeignAccess foreignAccess) {
+                this.clazz = clazz;
+                this.foreignAccess = foreignAccess;
+            }
+        }
 
-    private static final class TableEntry {
-        private final Class<? extends RTruffleObject> clazz;
-        private final ForeignAccess foreignAccess;
         /**
-         * {@link PolyglotEngine} checks the thread on a {@link ForeignAccess}.
+         * Table with a unique index for each class in {@link #FOREIGN_CLASSES}.
+         */
+        private static Class<?>[] classTable;
+        /**
+         * Isomorphic to {@link #classTable} but contains the {@link ForeignAccess} instance.
+         */
+        private final TableEntry[] table;
+        /**
+         * Mask to efficiently compute the table index.
+         */
+        @CompilationFinal private static int tableMask;
+        /**
+         * The thread that this state is generated for.
          */
         private final Thread thread;
 
-        private TableEntry(Class<? extends RTruffleObject> clazz, ForeignAccess foreignAccess) {
-            this.clazz = clazz;
+        private ForeignAccessState() {
             this.thread = Thread.currentThread();
-            this.foreignAccess = foreignAccess;
+            table = new TableEntry[classTable.length];
+            for (int i = 0; i < table.length; i++) {
+                @SuppressWarnings("unchecked")
+                Class<? extends RTruffleObject> checkedClass = (Class<? extends RTruffleObject>) classTable[i];
+                if (checkedClass != null) {
+                    table[i] = new TableEntry(checkedClass, createForeignAccess(checkedClass));
+                }
+            }
         }
-    }
 
-    TableEntry[] table = new TableEntry[32];
-    int tableIndex;
+        private ForeignAccess get(RTruffleObject obj) {
+            Class<? extends RTruffleObject> clazz = obj.getClass();
+            return get(clazz);
+        }
 
-    @Override
-    public ForeignAccess getForeignAccess(RTruffleObject obj) {
-        return get(obj);
-    }
+        private ForeignAccess get(Class<? extends RTruffleObject> clazz) {
+            int index = System.identityHashCode(clazz) & tableMask;
+            assert table[index].clazz == clazz;
+            return table[index].foreignAccess;
+        }
+
+        static {
+            generatePrototypeTable();
+        }
 
-    private synchronized ForeignAccess get(RTruffleObject obj) {
-        Class<? extends RTruffleObject> objclazz = obj.getClass();
-        Thread thread = Thread.currentThread();
-        for (int i = 0; i < tableIndex; i++) {
-            TableEntry te = table[i];
-            if (te.clazz == objclazz && te.thread == thread) {
-                return te.foreignAccess;
+        /**
+         * Create a table that has a unique index for every member of {@link #FOREIGN_CLASSES} for
+         * efficient access. Since {@link System#identityHashCode(Object)} can vary from run to run,
+         * the size of the table may vary, but is typically in the range 64-4096.
+         */
+        private static void generatePrototypeTable() {
+            int ts = 32;
+            while (true) {
+                classTable = new Class<?>[ts];
+                boolean collision = false;
+                for (int i = 0; i < FOREIGN_CLASSES.length; i++) {
+                    Class<?> clazz = FOREIGN_CLASSES[i];
+                    int h = System.identityHashCode(clazz);
+                    int hc = h % ts;
+                    if (classTable[hc] == null) {
+                        classTable[hc] = clazz;
+                    } else {
+                        collision = true;
+                        break;
+                    }
+                }
+                if (!collision) {
+                    break;
+                } else {
+                    ts = ts * 2;
+                }
             }
+            tableMask = ts - 1;
         }
-        return createForeignAccess(objclazz);
-    }
 
-    @TruffleBoundary
-    private ForeignAccess createForeignAccess(Class<? extends RTruffleObject> clazz) {
-        ForeignAccess foreignAccess = null;
-        String name = clazz.getSimpleName();
-        if (RNull.class.isAssignableFrom(clazz)) {
-            foreignAccess = RNullMRForeign.createAccess();
-        } else if (RList.class.isAssignableFrom(clazz)) {
-            foreignAccess = RListMRForeign.createAccess();
-        } else if (REnvironment.class.isAssignableFrom(clazz)) {
-            foreignAccess = REnvironmentMRForeign.createAccess();
-        } else if (RPairList.class.isAssignableFrom(clazz)) {
-            foreignAccess = RPairListMRForeign.createAccess();
-        } else if (RFunction.class.isAssignableFrom(clazz)) {
-            foreignAccess = RFunctionMRForeign.createAccess();
-        } else {
-            if (RAbstractVector.class.isAssignableFrom(clazz)) {
-                foreignAccess = ForeignAccess.create(RAbstractVector.class, new RAbstractVectorAccessFactory());
+        @TruffleBoundary
+        private static ForeignAccess createForeignAccess(Class<? extends RTruffleObject> clazz) {
+            ForeignAccess foreignAccess = null;
+            String name = clazz.getSimpleName();
+            if (RNull.class.isAssignableFrom(clazz)) {
+                foreignAccess = RNullMRForeign.createAccess();
+            } else if (RList.class.isAssignableFrom(clazz)) {
+                foreignAccess = RListMRForeign.createAccess();
+            } else if (REnvironment.class.isAssignableFrom(clazz)) {
+                foreignAccess = REnvironmentMRForeign.createAccess();
+            } else if (RPairList.class.isAssignableFrom(clazz)) {
+                foreignAccess = RPairListMRForeign.createAccess();
+            } else if (RFunction.class.isAssignableFrom(clazz)) {
+                foreignAccess = RFunctionMRForeign.createAccess();
+            } else if (DLL.DLLInfo.class.isAssignableFrom(clazz)) {
+                foreignAccess = DLLInfoMRForeign.createAccess();
+            } else if (DLL.DotSymbol.class.isAssignableFrom(clazz)) {
+                foreignAccess = DLLDotSymbolMRForeign.createAccess();
+            } else if (RSymbol.class.isAssignableFrom(clazz)) {
+                foreignAccess = RSymbolMRForeign.createAccess();
+            } else if (RExternalPtr.class.isAssignableFrom(clazz)) {
+                foreignAccess = RExternalPtrMRForeign.createAccess();
+            } else if (RUnboundValue.class.isAssignableFrom(clazz)) {
+                foreignAccess = RUnboundValueMRForeign.createAccess();
             } else {
-                throw RInternalError.unimplemented("foreignAccess: " + name);
+                if (RAbstractVector.class.isAssignableFrom(clazz)) {
+                    foreignAccess = ForeignAccess.create(RAbstractVector.class, new RAbstractVectorAccessFactory());
+                } else {
+                    throw RInternalError.unimplemented("foreignAccess: " + name);
+                }
             }
+            return foreignAccess;
         }
-        TableEntry te = new TableEntry(clazz, foreignAccess);
-        table[tableIndex++] = te;
-        return te.foreignAccess;
 
     }
 
+    /**
+     * In normal execution, there is only one thread.
+     */
+    private static final Assumption singleStateAssumption = Truffle.getRuntime().createAssumption("single ForeignAccessState");
+    /**
+     * In case of multiple threads, the per-thread state.
+     */
+    private static final ThreadLocal<ForeignAccessState> threadLocalState = new ThreadLocal<>();
+    /**
+     * In single thread mode, a fast path to the state. In multi-thread mode set to {@code null}.
+     */
+    @CompilationFinal private static ForeignAccessState singleForeignAccessState;
+
+    @Override
+    public ForeignAccess getForeignAccess(RTruffleObject obj) {
+        CompilerAsserts.neverPartOfCompilation("getForeignAccess");
+        ForeignAccessState foreignAccessState;
+        if (singleStateAssumption.isValid()) {
+            foreignAccessState = singleForeignAccessState;
+            if (foreignAccessState == null) {
+                // very first call
+                foreignAccessState = new ForeignAccessState();
+                singleForeignAccessState = foreignAccessState;
+                threadLocalState.set(foreignAccessState);
+            } else {
+                // check thread
+                if (Thread.currentThread() != foreignAccessState.thread) {
+                    singleStateAssumption.invalidate();
+                    singleForeignAccessState = null;
+                    foreignAccessState = new ForeignAccessState();
+                }
+            }
+        } else {
+            // use the threadLocal
+            foreignAccessState = threadLocalState.get();
+        }
+        ForeignAccess result = foreignAccessState.get(obj);
+        return result;
+    }
+
     @Override
     public Class<? extends TruffleLanguage<RContext>> getTruffleLanguage() {
         return TruffleRLanguage.class;
     }
+
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RListMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RListMR.java
index e1b29ff4d097c17b20b90f33cd768a97bfffcf2c..d694fbe0c4a3530bf847223c4379d3ee2fccdd9f 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RListMR.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RListMR.java
@@ -32,10 +32,10 @@ import com.oracle.truffle.r.engine.TruffleRLanguage;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.RCloseable;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RList;
 
 @MessageResolution(receiverType = RList.class, language = TruffleRLanguage.class)
@@ -106,12 +106,12 @@ public class RListMR {
     @Resolve(message = "KEYS")
     public abstract static class RListKeysNode extends Node {
         @Child private Node findContext = TruffleRLanguage.INSTANCE.actuallyCreateFindContextNode();
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+        @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
         @SuppressWarnings("try")
         protected Object access(RList receiver) {
             try (RCloseable c = RContext.withinContext(TruffleRLanguage.INSTANCE.actuallyFindContext0(findContext))) {
-                return receiver.getNames(attrProfiles);
+                return getNamesNode.getNames(receiver);
             }
         }
     }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java
new file mode 100644
index 0000000000000000000000000000000000000000..2eb3cb9661492abbde68aa3821eeb7a614028ec9
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.interop;
+
+import com.oracle.truffle.api.interop.CanResolve;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.engine.TruffleRLanguage;
+import com.oracle.truffle.r.runtime.data.RSymbol;
+
+@MessageResolution(receiverType = RSymbol.class, language = TruffleRLanguage.class)
+public class RSymbolMR {
+    @CanResolve
+    public abstract static class RSymbolCheck extends Node {
+
+        protected static boolean test(TruffleObject receiver) {
+            return receiver instanceof RSymbol;
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RUnboundValueMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RUnboundValueMR.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff0c179f53dafceb6e7ea0ca17e89896190b0fd2
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RUnboundValueMR.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.interop;
+
+import com.oracle.truffle.api.interop.CanResolve;
+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.engine.TruffleRLanguage;
+import com.oracle.truffle.r.runtime.data.RUnboundValue;
+
+@MessageResolution(receiverType = RUnboundValue.class, language = TruffleRLanguage.class)
+public class RUnboundValueMR {
+    @Resolve(message = "IS_BOXED")
+    public abstract static class RUnboundValueIsBoxedNode extends Node {
+        protected Object access(@SuppressWarnings("unused") RUnboundValue receiver) {
+            return false;
+        }
+    }
+
+    @Resolve(message = "HAS_SIZE")
+    public abstract static class RUnboundValueHasSizeNode extends Node {
+        protected Object access(@SuppressWarnings("unused") RUnboundValue receiver) {
+            return false;
+        }
+    }
+
+    @Resolve(message = "IS_NULL")
+    public abstract static class RUnboundValueIsNullNode extends Node {
+        protected Object access(@SuppressWarnings("unused") RUnboundValue receiver) {
+            return false;
+        }
+    }
+
+    @CanResolve
+    public abstract static class RUnboundValueCheck extends Node {
+
+        protected static boolean test(TruffleObject receiver) {
+            return receiver instanceof RUnboundValue;
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java
index 728a1efd4b830abf09db8db075cd947356ce93ed..72fe424293cbb87439f36e62ac18a963e59595d0 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/RGraphics.java
@@ -26,8 +26,8 @@ import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.FFIRootNode;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
  * A placeholder to keep {@code REngine} limited to calling the {@link #initialize} method. Two
@@ -64,7 +64,7 @@ public class RGraphics {
                 DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
                 DLL.SymbolHandle func = DLL.findSymbol("InitGraphics", null, rns);
                 assert func != DLL.SYMBOL_NOT_FOUND;
-                RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(new NativeCallInfo("InitGraphics", func, DLL.findLibrary("graphics")), new Object[0]);
+                FFIRootNode.createCallTarget().call(new NativeCallInfo("InitGraphics", func, DLL.findLibrary("graphics")), true, new Object[0]);
             }
         }
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
index 78338d6c6cc4335ed97664ba2bcbe401287e6105..d5b7d3673e414fdb57e61d873620e74941340b9a 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions.java
@@ -23,25 +23,31 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.ffi.GridRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
  * The .Call support for the grid package.
  */
 public class GridFunctions {
+
     public abstract static class InitGrid extends RExternalBuiltinNode.Arg1 {
+        @Child GridRFFI.GridRFFINode gridRFFINode = RFFIFactory.getRFFI().getGridRFFI().createGridRFFINode();
+
         @Specialization
         @TruffleBoundary
         protected Object initGrid(REnvironment gridEvalEnv) {
-            return RFFIFactory.getRFFI().getGridRFFI().initGrid(gridEvalEnv);
+            return gridRFFINode.initGrid(gridEvalEnv);
         }
     }
 
     public static final class KillGrid extends RExternalBuiltinNode {
+        @Child GridRFFI.GridRFFINode gridRFFINode = RFFIFactory.getRFFI().getGridRFFI().createGridRFFINode();
+
         @Override
         @TruffleBoundary
         public Object call(RArgsValuesAndNames args) {
-            return RFFIFactory.getRFFI().getGridRFFI().killGrid();
+            return gridRFFINode.killGrid();
         }
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
index 882a6fcf1d1dd0f31aaeb091c4e7c229d3b332e4..8aca802a24be27ab35c04541f29133abeaf55720 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
@@ -39,7 +39,6 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -307,10 +306,11 @@ public class MethodsListDispatch {
 
         public abstract Object executeObject(String name, REnvironment rho, String pckg);
 
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
         @Child private CastToVectorNode castToVector = CastToVectorNodeGen.create(false);
         @Child private ClassHierarchyScalarNode classHierarchyNode = ClassHierarchyScalarNodeGen.create();
         @Child private PromiseHelperNode promiseHelper;
+        @Child private GetFixedAttributeNode getGenericAttrNode = GetFixedAttributeNode.create(RRuntime.GENERIC_ATTR_KEY);
+        @Child private GetFixedAttributeNode getPckgAttrNode = GetFixedAttributeNode.create(RRuntime.PCKG_ATTR_KEY);
 
         @Specialization
         protected Object getGeneric(String name, REnvironment env, String pckg) {
@@ -327,9 +327,9 @@ public class MethodsListDispatch {
                 if (o != null) {
                     RAttributable vl = (RAttributable) o;
                     boolean ok = false;
-                    if (vl instanceof RFunction && vl.getAttr(attrProfiles, RRuntime.GENERIC_ATTR_KEY) != null) {
+                    if (vl instanceof RFunction && getGenericAttrNode.execute(vl) != null) {
                         if (pckg.length() > 0) {
-                            Object gpckgObj = vl.getAttr(attrProfiles, RRuntime.PCKG_ATTR_KEY);
+                            Object gpckgObj = getPckgAttrNode.execute(vl);
                             if (gpckgObj != null) {
                                 String gpckg = checkSingleString(castToVector.execute(gpckgObj), false, "The \"package\" slot in generic function object", this, classHierarchyNode);
                                 ok = pckg.equals(gpckg);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java
index 201f0d7d149f0946c17019e73cdccd860f6f9cc5..03eb4418b5467abf60e79721eda6931383cef8da 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java
@@ -25,7 +25,7 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
-// Transcribed from src/library/methods/slot.c
+// Transcribed from src/library/methods/src/slot.c
 
 public class Slot {
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cauchy.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cauchy.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ab4aaf4548915fe6de78d90ce103a82f522d559
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cauchy.java
@@ -0,0 +1,157 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 1998--2008, The R Core Team
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.MathConstants.M_PI;
+import static com.oracle.truffle.r.library.stats.TOMS708.fabs;
+
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_1;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_2;
+
+public final class Cauchy {
+    private Cauchy() {
+        // contains only static classes
+    }
+
+    public static final class RCauchy implements RandFunction2_Double {
+        @Override
+        public double evaluate(double location, double scale, RandomNumberProvider rand) {
+            if (Double.isNaN(location) || !Double.isFinite(scale) || scale < 0) {
+                return RMath.mlError();
+            }
+            if (scale == 0. || !Double.isFinite(location)) {
+                return location;
+            } else {
+                return location + scale * Math.tan(M_PI * rand.unifRand());
+            }
+        }
+    }
+
+    public static final class DCauchy implements Function3_1 {
+        @Override
+        public double evaluate(double x, double location, double scale, boolean giveLog) {
+            double y;
+            /* NaNs propagated correctly */
+            if (Double.isNaN(x) || Double.isNaN(location) || Double.isNaN(scale)) {
+                return x + location + scale;
+            }
+            if (scale <= 0) {
+                return RMath.mlError();
+            }
+
+            y = (x - location) / scale;
+            return giveLog ? -Math.log(M_PI * scale * (1. + y * y)) : 1. / (M_PI * scale * (1. + y * y));
+        }
+    }
+
+    public static final class PCauchy implements Function3_2 {
+        @Override
+        public double evaluate(double x, double location, double scale, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(x) || Double.isNaN(location) || Double.isNaN(scale)) {
+                return x + location + scale;
+            }
+
+            if (scale <= 0) {
+                return RMath.mlError();
+            }
+
+            x = (x - location) / scale;
+            if (Double.isNaN(x)) {
+                return RMath.mlError();
+            }
+
+            if (!Double.isFinite(x)) {
+                if (x < 0) {
+                    return DPQ.rdt0(lowerTail, logP);
+                } else {
+                    return DPQ.rdt1(lowerTail, logP);
+                }
+            }
+
+            if (!lowerTail) {
+                x = -x;
+            }
+
+            /*
+             * for large x, the standard formula suffers from cancellation. This is from Morten
+             * Welinder thanks to Ian Smith's atan(1/x) :
+             */
+
+            // GnuR has #ifdef HAVE_ATANPI where it uses atanpi function, here we only implement the
+            // case when atanpi is not available for the moment
+            if (fabs(x) > 1) {
+                double y = Math.atan(1 / x) / M_PI;
+                return (x > 0) ? DPQ.rdclog(y, logP) : DPQ.rdval(-y, logP);
+            } else {
+                return DPQ.rdval(0.5 + Math.atan(x) / M_PI, logP);
+            }
+        }
+    }
+
+    public static final class QCauchy implements Function3_2 {
+        @Override
+        public double evaluate(double p, double location, double scale, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(p) || Double.isNaN(location) || Double.isNaN(scale)) {
+                return p + location + scale;
+            }
+            try {
+                DPQ.rqp01check(p, logP);
+            } catch (EarlyReturn e) {
+                return e.result;
+            }
+            if (scale <= 0 || !Double.isFinite(scale)) {
+                if (scale == 0) {
+                    return location;
+                }
+                return RMath.mlError();
+            }
+
+            if (logP) {
+                if (p > -1) {
+                    /*
+                     * when ep := Math.exp(p), tan(pi*ep)= -tan(pi*(-ep))= -tan(pi*(-ep)+pi) =
+                     * -tan(pi*(1-ep)) = = -tan(pi*(-Math.expm1(p)) for p ~ 0, Math.exp(p) ~ 1,
+                     * tan(~0) may be better than tan(~pi).
+                     */
+                    if (p == 0.) {
+                        /* needed, since 1/tan(-0) = -Inf for some arch. */
+                        return location + (lowerTail ? scale : -scale) * Double.POSITIVE_INFINITY;
+                    }
+                    lowerTail = !lowerTail;
+                    p = -Math.expm1(p);
+                } else {
+                    p = Math.exp(p);
+                }
+            } else {
+                if (p > 0.5) {
+                    if (p == 1.) {
+                        return location + (lowerTail ? scale : -scale) * Double.POSITIVE_INFINITY;
+                    }
+                    p = 1 - p;
+                    lowerTail = !lowerTail;
+                }
+            }
+
+            if (p == 0.5) {
+                return location;
+            } // avoid 1/Inf below
+            if (p == 0.) {
+                return location + (lowerTail ? scale : -scale) * Double.NEGATIVE_INFINITY;
+            } // p = 1. is handled above
+            return location + (lowerTail ? -scale : scale) / RMath.tanpi(p);
+            /* -1/tan(pi * p) = -cot(pi * p) = tan(pi * (p - 1/2)) */
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
index d4c6dba39241d1d16c7527650a7bcbec5a5c9434..9094f3e34ff8d521a8ec586a20f0686e6d561c10 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
@@ -17,8 +17,10 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetAttributeNodeGen;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -33,6 +35,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
     private static final NACheck naCheck = NACheck.create();
 
+    @Child private GetFixedAttributeNode getNamesAttrNode = GetFixedAttributeNode.createNames();
+
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg(0).asDoubleVector();
@@ -44,21 +48,24 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
     @Specialization(guards = "method == cachedMethod")
     protected RDoubleVector cdist(RAbstractDoubleVector x, @SuppressWarnings("unused") int method, RList list, double p, @SuppressWarnings("unused") @Cached("method") int cachedMethod,
                     @Cached("getMethod(method)") Method methodObj,
-                    @Cached("create()") SetAttributeNode setAttrNode) {
-        int nr = RRuntime.nrows(x);
-        int nc = RRuntime.ncols(x);
+                    @Cached("create()") SetAttributeNode setAttrNode,
+                    @Cached("create()") SetClassAttributeNode setClassAttrNode,
+                    @Cached("create()") GetDimAttributeNode getDimNode) {
+        int nr = getDimNode.nrows(x);
+        int nc = getDimNode.ncols(x);
         int n = nr * (nr - 1) / 2; /* avoid int overflow for N ~ 50,000 */
         double[] ans = new double[n];
         RDoubleVector xm = x.materialize();
         rdistance(xm.getDataWithoutCopying(), nr, nc, ans, false, methodObj, p);
         RDoubleVector result = RDataFactory.createDoubleVector(ans, naCheck.neverSeenNA());
         DynamicObject resultAttrs = result.initAttributes();
-        RStringVector names = (RStringVector) list.getAttr(RRuntime.NAMES_ATTR_KEY);
+
+        RStringVector names = (RStringVector) getNamesAttrNode.execute(list);
         for (int i = 0; i < names.getLength(); i++) {
             String name = names.getDataAt(i);
             Object listValue = list.getDataAt(i);
             if (name.equals(RRuntime.CLASS_ATTR_KEY)) {
-                result.setClassAttr(listValue instanceof RStringVector ? (RStringVector) listValue : RDataFactory.createStringVectorFromScalar((String) listValue));
+                setClassAttrNode.execute(result, listValue instanceof RStringVector ? (RStringVector) listValue : RDataFactory.createStringVectorFromScalar((String) listValue));
             } else {
                 setAttrNode.execute(resultAttrs, name, listValue);
             }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Chisq.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Chisq.java
new file mode 100644
index 0000000000000000000000000000000000000000..c39fa8c5e71ef0ff5c84add184ea21ccee6cd3df
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Chisq.java
@@ -0,0 +1,34 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 2000, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.GammaFunctions.dgamma;
+import static com.oracle.truffle.r.library.stats.GammaFunctions.pgamma;
+
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_1;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_2;
+
+public final class Chisq {
+    public static final class PChisq implements Function2_2 {
+        @Override
+        public double evaluate(double x, double df, boolean lowerTail, boolean logP) {
+            return pgamma(x, df / 2., 2., lowerTail, logP);
+        }
+    }
+
+    public static final class DChisq implements Function2_1 {
+        @Override
+        public double evaluate(double x, double df, boolean giveLog) {
+            return dgamma(x, df / 2., 2., giveLog);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
index 1aff0091ef52ff496d09f462d7c2a1fd8db2e4dd..5080206bbed26ecd787667839af2adae4bfe9f3f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
@@ -22,6 +22,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -76,6 +77,8 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
     private final BranchProfile error = BranchProfile.create();
     private final BranchProfile warning = BranchProfile.create();
 
+    @Child private GetDimAttributeNode getDimsNode = GetDimAttributeNode.create();
+
     private final LoopConditionProfile loopLength = LoopConditionProfile.createCountingProfile();
 
     public RDoubleVector corcov(RDoubleVector x, RDoubleVector y, @SuppressWarnings("unused") int method, boolean iskendall, RBaseNode invokingNode) throws RError {
@@ -175,14 +178,14 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         return ans;
     }
 
-    private static int ncols(RDoubleVector x) {
+    private int ncols(RDoubleVector x) {
         assert x.isMatrix();
-        return x.getDimensions()[1];
+        return getDimsNode.getDimensions(x)[1];
     }
 
-    private static int nrows(RDoubleVector x) {
+    private int nrows(RDoubleVector x) {
         assert x.isMatrix();
-        return x.getDimensions()[0];
+        return getDimsNode.getDimensions(x)[0];
     }
 
     private void complete1(int n, int ncx, RDoubleVector x, RIntVector ind, boolean naFail) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
index 2887c8f67d5837b4fe5f76b91940f39a199ac373..8c291da19ee516d98b50441e98361f0af40b22b1 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
@@ -10,10 +10,11 @@
  */
 package com.oracle.truffle.r.library.stats;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -29,7 +30,7 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
     }
 
     @Specialization
-    protected RIntVector cutree(RAbstractIntVector mergeIn, RAbstractIntVector whichIn) {
+    protected RIntVector cutree(RAbstractIntVector mergeIn, RAbstractIntVector whichIn, @Cached("create()") GetDimAttributeNode getDimNode) {
         RIntVector merge = mergeIn.materialize();
         RIntVector which = whichIn.materialize();
         int whichLen = which.getLength();
@@ -43,7 +44,7 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
         int mm = 0;
         boolean foundJ;
 
-        int n = RRuntime.nrows(merge) + 1;
+        int n = getDimNode.nrows(merge) + 1;
         /*
          * The C code uses 1-based indices for the next three arrays and so set the int * value
          * behind the actual start of the array. To keep the logic equivalent, we call adj(k) on the
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DBeta.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DBeta.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6a5a767d9e71e9bf4b8f8baa772bdaaf1124178
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DBeta.java
@@ -0,0 +1,95 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 2000--2014, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+// Acknowledgement from GnuR header:
+// Author: Catherine Loader, catherine@research.bell-labs.com, October 23, 2000.
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.LBeta.lbeta;
+
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_1;
+
+public class DBeta implements Function3_1 {
+    @Override
+    public double evaluate(double x, double a, double b, boolean log) {
+        /* NaNs propagated correctly */
+        if (Double.isNaN(x) || Double.isNaN(a) || Double.isNaN(b)) {
+            return x + a + b;
+        }
+
+        if (a < 0 || b < 0) {
+            return RMath.mlError();
+        }
+        if (x < 0 || x > 1) {
+            return (DPQ.rd0(log));
+        }
+
+        // limit cases for (a,b), leading to point masses
+        if (a == 0 || b == 0 || !Double.isFinite(a) || !Double.isFinite(b)) {
+            if (a == 0 && b == 0) { // point mass 1/2 at each of {0,1} :
+                if (x == 0 || x == 1) {
+                    return Double.POSITIVE_INFINITY;
+                } else {
+                    return DPQ.rd0(log);
+                }
+            }
+            if (a == 0 || a / b == 0) { // point mass 1 at 0
+                if (x == 0) {
+                    return Double.POSITIVE_INFINITY;
+                } else {
+                    return DPQ.rd0(log);
+                }
+            }
+            if (b == 0 || b / a == 0) { // point mass 1 at 1
+                if (x == 1) {
+                    return Double.POSITIVE_INFINITY;
+                } else {
+                    return DPQ.rd0(log);
+                }
+            }
+            // else, remaining case: a = b = Inf : point mass 1 at 1/2
+            if (x == 0.5) {
+                return Double.POSITIVE_INFINITY;
+            } else {
+                return DPQ.rd0(log);
+            }
+        }
+
+        if (x == 0) {
+            if (a > 1) {
+                return DPQ.rd0(log);
+            }
+            if (a < 1) {
+                return Double.POSITIVE_INFINITY;
+            }
+            /* a == 1 : */
+            return DPQ.rdval(b, log);
+        }
+        if (x == 1) {
+            if (b > 1) {
+                return DPQ.rd0(log);
+            }
+            if (b < 1) {
+                return Double.POSITIVE_INFINITY;
+            }
+            /* b == 1 : */
+            return (DPQ.rdval(a, log));
+        }
+
+        double lval;
+        if (a <= 2 || b <= 2) {
+            lval = (a - 1) * Math.log(x) + (b - 1) * Math.log1p(-x) - lbeta(a, b);
+        } else {
+            lval = Math.log(a + b - 1) + Dbinom.dbinomRaw(a - 1, a + b - 2, x, 1 - x, true);
+        }
+
+        return DPQ.rdexp(lval, log);
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPQ.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPQ.java
index c033762f79c827e92511b4ef33ba34de874e2d4b..4925be2e7668b809c858a9ab8357bf45df62bcdb 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPQ.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPQ.java
@@ -10,120 +10,120 @@
  */
 package com.oracle.truffle.r.library.stats;
 
+import static com.oracle.truffle.r.library.stats.MathConstants.M_LN2;
+
 import com.oracle.truffle.api.nodes.ControlFlowException;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 
-// transcribed from dpq.h
-
+/**
+ * Contains macros transcribed from dpq.h. Naming convention is all lowercase and remove underscores
+ * from GnuR name. Some macros change control flow by explicitly returning, this is handled by
+ * throwing {@link EarlyReturn} exception that encapsulates the desired return value.
+ */
 public final class DPQ {
     private DPQ() {
-        // private
+        // only static methods
+    }
+
+    public static final class EarlyReturn extends ControlFlowException {
+        private static final long serialVersionUID = 1182697355931636213L;
+        public final double result;
+
+        private EarlyReturn(double result) {
+            this.result = result;
+        }
     }
 
     // R >= 3.1.0: # define R_nonint(x) (fabs((x) - R_forceint(x)) > 1e-7)
+    // Note: if true should be followed by "return d0(logP)", consider using nointCheck instead
     public static boolean nonint(double x) {
         return Math.abs(x - Math.round(x)) > 1e-7 * Math.max(1., Math.abs(x));
     }
 
     // R_D__0
-    public static double d0(boolean logP) {
+    public static double rd0(boolean logP) {
         return logP ? Double.NEGATIVE_INFINITY : 0.;
     }
 
     // R_D__1
-    public static double d1(boolean logP) {
+    public static double rd1(boolean logP) {
         return logP ? 0. : 1.;
     }
 
     // R_DT_0
-    public static double dt0(boolean logP, boolean lowerTail) {
-        return lowerTail ? d0(logP) : d1(logP);
+    public static double rdt0(boolean lowerTail, boolean logP) {
+        return lowerTail ? rd0(logP) : rd1(logP);
     }
 
-    // R_DT_1
-    public static double dt1(boolean logP, boolean lowerTail) {
-        return lowerTail ? d1(logP) : d0(logP);
+    // R_D_log
+    public static double rdlog(double p, boolean logP) {
+        return logP ? p : Math.log(p);
     }
 
-    /* Use 0.5 - p + 0.5 to perhaps gain 1 bit of accuracy */
+    public static double rdtlog(double p, boolean lowerTail, boolean logp) {
+        return lowerTail ? rdlog(p, logp) : rdlexp(p, logp);
+    }
+
+    // R_DT_1
+    public static double rdt1(boolean lowerTail, boolean logP) {
+        return lowerTail ? rd1(logP) : rd0(logP);
+    }
 
     // R_D_Lval
-    public static double dLval(boolean lowerTail, double p) {
+    public static double rdlval(double p, boolean lowerTail) {
         return lowerTail ? p : 0.5 - p + 0.5;
     }
 
-    public static double dCval(double p, boolean lowerTail) {
+    public static double rdcval(double p, boolean lowerTail) {
         return lowerTail ? 0.5 - p + 0.5 : p; /* 1 - p */
     }
 
-    //
-    public static double dVal(double x, boolean logP) {
+    // R_D_val
+    public static double rdval(double x, boolean logP) {
         return logP ? Math.log(x) : x; /* x in pF(x,..) */
     }
 
-    // #define R_D_qIv(p) (log_p ? exp(p) : (p)) /* p in qF(p,..) */
-    // R_D_exp
-    public static double dExp(double x, boolean logP) {
+    public static double rdexp(double x, boolean logP) {
         return logP ? x : Math.exp(x); /* exp(x) */
     }
 
-    // #define R_D_log(p) (log_p ? (p) : log(p)) /* log(p) */
-    public static double dClog(double p, boolean logP) {
-        return logP ? Math.log1p(-p) : 0.5 - p + 0.5; /* [log](1-p) */
+    // R_D_LExp
+    public static double rdlexp(double x, boolean logP) {
+        return (logP ? rlog1exp(x) : RMath.log1p(-x));
     }
 
-    //
-    // // log(1 - exp(x)) in more stable form than log1p(- R_D_qIv(x)) :
-    // #define R_Log1_Exp(x) ((x) > -M_LN2 ? log(-expm1(x)) : log1p(-exp(x)))
-    //
-    // #define R_D_LExp(x) (log_p ? R_Log1_Exp(x) : log1p(-x))
-    //
-    // #define R_DT_val(x) (lower_tail ? R_D_val(x) : R_D_Clog(x))
-    public static double dtCval(double x, boolean lowerTail, boolean logP) {
-        return lowerTail ? dClog(x, logP) : dVal(x, logP);
+    public static double rdfexp(double f, double x, boolean giveLog) {
+        return giveLog ? -0.5 * Math.log(f) + x : Math.exp(x) / Math.sqrt(f);
     }
 
-    //
-    // R_DT_qIv
-    public static double dtQIv(double p, boolean lowerTail, boolean logP) {
-        return logP ? lowerTail ? Math.exp(p) : -Math.expm1(p) : dLval(lowerTail, p);
+    // R_Log1_Exp
+    public static double rlog1exp(double x) {
+        return ((x) > -M_LN2 ? Math.log(-RMath.expm1(x)) : RMath.log1p(-Math.exp(x)));
     }
 
-    // /*#define R_DT_CIv(p) R_D_Cval(R_D_qIv(p)) * 1 - p in qF */
-
-    public static double dtCIv(double p, boolean lowerTail, boolean logP) {
-        return logP ? lowerTail ? -Math.expm1(p) : Math.exp(p) : dCval(p, lowerTail);
+    // R_DT_Clog
+    public static double rdtclog(double p, boolean lowerTail, boolean logP) {
+        return lowerTail ? rdlexp(p, logP) : rdlog(p, logP);
     }
 
-    //
-    // #define R_DT_exp(x) R_D_exp(R_D_Lval(x)) /* exp(x) */
-    // #define R_DT_Cexp(x) R_D_exp(R_D_Cval(x)) /* exp(1 - x) */
-    //
-    // #define R_DT_log(p) (lower_tail? R_D_log(p) : R_D_LExp(p))/* log(p) in qF */
-    // #define R_DT_Clog(p) (lower_tail? R_D_LExp(p): R_D_log(p))/* log(1-p) in qF*/
-    // #define R_DT_Log(p) (lower_tail? (p) : R_Log1_Exp(p))
+    // R_D_Clog(p) (log_p ? log1p(-(p)) : (0.5 - (p) + 0.5)) /* [log](1-p) */
+    public static double rdclog(double p, boolean logP) {
+        return logP ? RMath.log1p(-(p)) : (0.5 - (p) + 0.5);
+    }
 
-    public static final class EarlyReturn extends ControlFlowException {
-        private static final long serialVersionUID = 1182697355931636213L;
-        public final double result;
+    // R_DT_qIv
+    public static double rdtqiv(double p, boolean lowerTail, boolean logP) {
+        return logP ? lowerTail ? Math.exp(p) : -Math.expm1(p) : rdlval(p, lowerTail);
+    }
 
-        private EarlyReturn(double result) {
-            this.result = result;
-        }
+    // R_DT_CIv
+    public static double rdtciv(double p, boolean lowerTail, boolean logP) {
+        return logP ? lowerTail ? -Math.expm1(p) : Math.exp(p) : rdcval(p, lowerTail);
     }
 
-    /*
-     * Do the boundaries exactly for q*() functions : Often _LEFT_ = ML_NEGINF , and very often
-     * _RIGHT_ = ML_POSINF;
-     *
-     * R_Q_P01_boundaries(p, _LEFT_, _RIGHT_) :<==>
-     *
-     * R_Q_P01_check(p); if (p == R_DT_0) return _LEFT_ ; if (p == R_DT_1) return _RIGHT_;
-     *
-     * the following implementation should be more efficient (less tests):
-     */
-    public static void qP01Boundaries(double p, double left, double right, boolean lowerTail, boolean logP) throws EarlyReturn {
+    // R_Q_P01_boundaries
+    public static void rqp01boundaries(double p, double left, double right, boolean lowerTail, boolean logP) throws EarlyReturn {
         if (logP) {
             if (p > 0) {
                 throw new EarlyReturn(Double.NaN);
@@ -148,17 +148,32 @@ public final class DPQ {
         }
     }
 
-    /* [neg]ative or [non int]eger : */
-    public static boolean dNegInonint(double x) {
-        return x < 0 || nonint(x);
+    // R_Q_P01_check
+    public static void rqp01check(double p, boolean logP) throws EarlyReturn {
+        if ((logP && p > 0) || (!logP && (p < 0 || p > 1))) {
+            throw new EarlyReturn(RMath.mlError());
+        }
+    }
+
+    // Unimplemented macros:
+    //
+    // #define R_DT_exp(x) R_D_exp(R_D_Lval(x)) /* exp(x) */
+    // #define R_DT_Cexp(x) R_D_exp(R_D_Cval(x)) /* exp(1 - x) */
+    //
+    // #define R_DT_log(p) (lower_tail? R_D_log(p) : R_D_LExp(p))/* log(p) in qF */
+    // #define R_DT_Clog(p) (lower_tail? R_D_LExp(p): R_D_log(p))/* log(1-p) in qF*/
+    // #define R_DT_Log(p) (lower_tail? (p) : R_Log1_Exp(p))
+
+    // FastR helpers:
+
+    public static void nointCheckWarning(double x, String varName) {
+        RError.warning(RError.SHOW_CALLER, Message.NON_INTEGER_N, varName, x);
     }
 
-    // for discrete d<distr>(x, ...) :
-    public static boolean dNonintCheck(double x) {
+    public static void nonintCheck(double x, boolean giveLog) throws EarlyReturn {
         if (nonint(x)) {
-            RError.warning(RError.SHOW_CALLER, Message.NON_INTEGER_N, "x", x);
-            return true;
+            nointCheckWarning(x, "x");
+            throw new EarlyReturn(rd0(giveLog));
         }
-        return false;
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPois.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPois.java
new file mode 100644
index 0000000000000000000000000000000000000000..b01d2a4d75603a4b862849e498ef24a41ce0e167
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPois.java
@@ -0,0 +1,42 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 2000--2014, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+// Acknowledgement from GnuR header:
+// Author: Catherine Loader, catherine@research.bell-labs.com, October 23, 2000.
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.GammaFunctions.dpoisRaw;
+import static com.oracle.truffle.r.library.stats.MathConstants.forceint;
+
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_1;
+
+public final class DPois implements Function2_1 {
+    @Override
+    public double evaluate(double x, double lambda, boolean giveLog) {
+        if (Double.isNaN(x) || Double.isNaN(lambda)) {
+            return x + lambda;
+        }
+        if (lambda < 0) {
+            return RMath.mlError();
+        }
+
+        try {
+            DPQ.nonintCheck(x, giveLog);
+        } catch (EarlyReturn e) {
+            return e.result;
+        }
+        if (x < 0 || !Double.isFinite(x)) {
+            return DPQ.rd0(giveLog);
+        }
+
+        return dpoisRaw(forceint(x), lambda, giveLog);
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dbinom.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dbinom.java
index 4ea79d16d4908eeba50da3b7d8f2ae4937feb969..509f543c81aeb163e1eb86ccf6725ea40a88f95d 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dbinom.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dbinom.java
@@ -17,6 +17,7 @@
 package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
 
 // transcribed from dbinom.c
 
@@ -24,28 +25,28 @@ public final class Dbinom implements StatsFunctions.Function3_1 {
 
     private final BranchProfile nanProfile = BranchProfile.create();
 
-    private static double dbinomRaw(double x, double n, double p, double q, boolean giveLog) {
+    public static double dbinomRaw(double x, double n, double p, double q, boolean giveLog) {
 
         if (p == 0) {
-            return ((x == 0) ? DPQ.d1(giveLog) : DPQ.d0(giveLog));
+            return ((x == 0) ? DPQ.rd1(giveLog) : DPQ.rd0(giveLog));
         }
         if (q == 0) {
-            return ((x == n) ? DPQ.d1(giveLog) : DPQ.d0(giveLog));
+            return ((x == n) ? DPQ.rd1(giveLog) : DPQ.rd0(giveLog));
         }
 
         if (x == 0) {
             if (n == 0) {
-                return DPQ.d1(giveLog);
+                return DPQ.rd1(giveLog);
             }
             double lc = (p < 0.1) ? -GammaFunctions.bd0(n, n * q) - n * p : n * Math.log(q);
-            return DPQ.dExp(lc, giveLog);
+            return DPQ.rdexp(lc, giveLog);
         }
         if (x == n) {
             double lc = (q < 0.1) ? -GammaFunctions.bd0(n, n * p) - n * q : n * Math.log(p);
-            return DPQ.dExp(lc, giveLog);
+            return DPQ.rdexp(lc, giveLog);
         }
         if (x < 0 || x > n) {
-            return DPQ.d0(giveLog);
+            return DPQ.rd0(giveLog);
         }
 
         /*
@@ -61,7 +62,7 @@ public final class Dbinom implements StatsFunctions.Function3_1 {
          */
         double lf = MathConstants.M_LN_2PI + Math.log(x) + Math.log1p(-x / n);
 
-        return DPQ.dExp(lc - 0.5 * lf, giveLog);
+        return DPQ.rdexp(lc - 0.5 * lf, giveLog);
     }
 
     @Override
@@ -72,12 +73,19 @@ public final class Dbinom implements StatsFunctions.Function3_1 {
             return x + n + p;
         }
 
-        if (p < 0 || p > 1 || DPQ.dNegInonint(n)) {
+        if (p < 0 || p > 1 || n < 0 || DPQ.nonint(n)) {
             nanProfile.enter();
             return Double.NaN;
         }
-        if (DPQ.dNonintCheck(x) || x < 0 || !Double.isFinite(x)) {
-            return DPQ.d0(giveLog);
+
+        try {
+            DPQ.nonintCheck(x, giveLog);
+        } catch (EarlyReturn e) {
+            return e.result;
+        }
+
+        if (x < 0 || !Double.isFinite(x)) {
+            return DPQ.rd0(giveLog);
         }
 
         return dbinomRaw(MathConstants.forceint(x), MathConstants.forceint(n), p, 1 - p, giveLog);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Df.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Df.java
new file mode 100644
index 0000000000000000000000000000000000000000..ded5ed50571f78b97300e4c76b7d0cdab74cb34c
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Df.java
@@ -0,0 +1,70 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 2000--2014, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+// Acknowledgement from GnuR header:
+// Author: Catherine Loader, catherine@research.bell-labs.com, October 23, 2000.
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.Dbinom.dbinomRaw;
+import static com.oracle.truffle.r.library.stats.GammaFunctions.dgamma;
+
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_1;
+
+public final class Df implements Function3_1 {
+    @Override
+    public double evaluate(double x, double m, double n, boolean giveLog) {
+        double p;
+        double q;
+        double f;
+        double dens;
+
+        if (Double.isNaN(x) || Double.isNaN(m) || Double.isNaN(n)) {
+            return x + m + n;
+        }
+
+        if (m <= 0 || n <= 0) {
+            return RMath.mlError();
+        }
+        if (x < 0.) {
+            return DPQ.rd0(giveLog);
+        }
+        if (x == 0.) {
+            return m > 2 ? DPQ.rd0(giveLog) : (m == 2 ? DPQ.rd1(giveLog) : Double.POSITIVE_INFINITY);
+        }
+        if (!Double.isFinite(m) && !Double.isFinite(n)) { /* both +Inf */
+            if (x == 1.) {
+                return Double.POSITIVE_INFINITY;
+            } else {
+                return DPQ.rd0(giveLog);
+            }
+        }
+        if (!Double.isFinite(n)) {
+            /* must be +Inf by now */
+            return dgamma(x, m / 2, 2. / m, giveLog);
+        }
+        if (m > 1e14) { /* includes +Inf: code below is inaccurate there */
+            dens = dgamma(1. / x, n / 2, 2. / n, giveLog);
+            return giveLog ? dens - 2 * Math.log(x) : dens / (x * x);
+        }
+
+        f = 1. / (n + x * m);
+        q = n * f;
+        p = x * m * f;
+
+        if (m >= 2) {
+            f = m * q / 2;
+            dens = dbinomRaw((m - 2) / 2, (m + n - 2) / 2, p, q, giveLog);
+        } else {
+            f = m * m * q / (2 * p * (m + n));
+            dens = dbinomRaw(m / 2, (m + n) / 2, p, q, giveLog);
+        }
+        return (giveLog ? Math.log(f) + dens : f * dens);
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
index 01a1f747831be975f900f91e34525d9d0cc6dd20..b33d733a7cb6b25fac7190bc27dcaca9a1830b73 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
@@ -10,10 +10,11 @@
  */
 package com.oracle.truffle.r.library.stats;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
@@ -25,9 +26,9 @@ public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
     }
 
     @Specialization
-    protected RDoubleVector doubleCentre(RAbstractDoubleVector aVecAbs) {
+    protected RDoubleVector doubleCentre(RAbstractDoubleVector aVecAbs, @Cached("create()") GetDimAttributeNode getDimNode) {
         RDoubleVector aVec = aVecAbs.materialize();
-        int n = RRuntime.nrows(aVec);
+        int n = getDimNode.nrows(aVec);
         double[] a = aVec.getDataWithoutCopying(); // does not copy
 
         for (int i = 0; i < n; i++) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dt.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dt.java
new file mode 100644
index 0000000000000000000000000000000000000000..62245897573ddf9e784b89fd9b97acd1d21fa249
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dt.java
@@ -0,0 +1,77 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 2000--2014, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+// Acknowledgement from GnuR header:
+// Author: Catherine Loader, catherine@research.bell-labs.com, October 23, 2000.
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.GammaFunctions.bd0;
+import static com.oracle.truffle.r.library.stats.GammaFunctions.dnorm;
+import static com.oracle.truffle.r.library.stats.GammaFunctions.stirlerr;
+import static com.oracle.truffle.r.library.stats.MathConstants.DBL_EPSILON;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_1_SQRT_2PI;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_LN_SQRT_2PI;
+
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_1;
+
+public final class Dt implements Function2_1 {
+    @Override
+    public double evaluate(double x, double n, boolean giveLog) {
+        if (Double.isNaN(x) || Double.isNaN(n)) {
+            return x + n;
+        }
+
+        if (n <= 0) {
+            return RMath.mlError();
+        }
+
+        if (!Double.isFinite(x)) {
+            return DPQ.rd0(giveLog);
+        }
+        if (!Double.isFinite(n)) {
+            return dnorm(x, 0., 1., giveLog);
+        }
+
+        double u;
+        double t = -bd0(n / 2., (n + 1) / 2.) + stirlerr((n + 1) / 2.) - stirlerr(n / 2.);
+        double x2n = x * x / n; // in [0, Inf]
+        double ax = 0.; // <- -Wpedantic
+        double lx2n; // := Math.log(Math.sqrt(1 + x2n)) = Math.log(1 + x2n)/2
+        boolean lrgx2n = (x2n > 1. / DBL_EPSILON);
+        if (lrgx2n) { // large x^2/n :
+            ax = Math.abs(x);
+            lx2n = Math.log(ax) - Math.log(n) / 2.; // = Math.log(x2n)/2 = 1/2 * Math.log(x^2 / n)
+            u = // Math.log(1 + x2n) * n/2 = n * Math.log(1 + x2n)/2 =
+                            n * lx2n;
+        } else if (x2n > 0.2) {
+            lx2n = Math.log(1 + x2n) / 2.;
+            u = n * lx2n;
+        } else {
+            lx2n = Math.log1p(x2n) / 2.;
+            u = -bd0(n / 2., (n + x * x) / 2.) + x * x / 2.;
+        }
+
+        // old: return R_D_fMath.exp(M_2PI*(1+x2n), t-u);
+
+        // R_D_fMath.exp(f,x) := (give_Math.log ? -0.5*Math.log(f)+(x) : Math.exp(x)/Math.sqrt(f))
+        // f = 2pi*(1+x2n)
+        // ==> 0.5*Math.log(f) = Math.log(2pi)/2 + Math.log(1+x2n)/2 = Math.log(2pi)/2 + l_x2n
+        // 1/Math.sqrt(f) = 1/Math.sqrt(2pi * (1+ x^2 / n))
+        // = 1/Math.sqrt(2pi)/(|x|/Math.sqrt(n)*Math.sqrt(1+1/x2n))
+        // = M_1_SQRT_2PI * Math.sqrt(n)/ (|x|*Math.sqrt(1+1/x2n))
+        if (giveLog) {
+            return t - u - (M_LN_SQRT_2PI + lx2n);
+        }
+
+        // else : if(lrg_x2n) : Math.sqrt(1 + 1/x2n) ='= Math.sqrt(1) = 1
+        double tmp = (lrgx2n ? Math.sqrt(n) / ax : Math.exp(-lx2n));
+        return Math.exp(t - u) * M_1_SQRT_2PI * tmp;
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Exp.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Exp.java
new file mode 100644
index 0000000000000000000000000000000000000000..05c81882607860c2964fcd497ca817555579a8b3
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Exp.java
@@ -0,0 +1,95 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 2000, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction1_Double;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_1;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_2;
+
+public class Exp {
+    public static final class DExp implements Function2_1 {
+        @Override
+        public double evaluate(double x, double scale, boolean giveLog) {
+            /* NaNs propagated correctly */
+            if (Double.isNaN(x) || Double.isNaN(scale)) {
+                return x + scale;
+            }
+
+            if (scale <= 0.0) {
+                return RMath.mlError();
+            }
+
+            if (x < 0.) {
+                return DPQ.rd0(giveLog);
+            }
+            return (giveLog ? (-x / scale) - Math.log(scale) : Math.exp(-x / scale) / scale);
+        }
+    }
+
+    public static final class RExp implements RandFunction1_Double {
+        @Override
+        public double evaluate(double scale, RandomNumberProvider rand) {
+            if (!Double.isFinite(scale) || scale <= 0.0) {
+                return scale == 0. ? 0. : RMath.mlError();
+            }
+            return scale * rand.expRand();
+        }
+    }
+
+    public static final class PExp implements Function2_2 {
+        @Override
+        public double evaluate(double x, double scale, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(x) || Double.isNaN(scale)) {
+                return x + scale;
+            }
+            if (scale < 0) {
+                return RMath.mlError();
+            }
+
+            if (x <= 0.) {
+                return DPQ.rdt0(lowerTail, logP);
+            }
+
+            /* same as weibull( shape = 1): */
+            x = -(x / scale);
+            return lowerTail ? (logP ? DPQ.rlog1exp(x) : -RMath.expm1(x)) : DPQ.rdexp(x, logP);
+        }
+    }
+
+    public static final class QExp implements Function2_2 {
+        @Override
+        public double evaluate(double p, double scale, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(p) || Double.isNaN(scale)) {
+                return p + scale;
+            }
+
+            if (scale < 0) {
+                return RMath.mlError();
+            }
+
+            try {
+                DPQ.rqp01check(p, logP);
+            } catch (EarlyReturn e) {
+                return e.result;
+            }
+
+            if (p == DPQ.rdt0(lowerTail, logP)) {
+                return 0;
+            }
+
+            return -scale * DPQ.rdtclog(p, lowerTail, logP);
+
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/GammaFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/GammaFunctions.java
index bdad479b98efd9546b467c40cfb17ba753dc7e19..1638c38e2ce080d756db52c1c368bd0c9044230a 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/GammaFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/GammaFunctions.java
@@ -18,29 +18,26 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import static com.oracle.truffle.r.library.stats.StatsUtil.DBLEPSILON;
-import static com.oracle.truffle.r.library.stats.StatsUtil.M_1_SQRT_2PI;
-import static com.oracle.truffle.r.library.stats.StatsUtil.M_2PI;
-import static com.oracle.truffle.r.library.stats.StatsUtil.M_LN2;
-import static com.oracle.truffle.r.library.stats.StatsUtil.M_SQRT_32;
-import static com.oracle.truffle.r.library.stats.StatsUtil.chebyshevEval;
-import static com.oracle.truffle.r.library.stats.StatsUtil.expm1;
-import static com.oracle.truffle.r.library.stats.StatsUtil.fmax2;
-import static com.oracle.truffle.r.library.stats.StatsUtil.log1p;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rd0;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rd1;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdexp;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdfexp;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdt0;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdt1;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdtclog;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdtlog;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdtqiv;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rlog1exp;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rqp01check;
+import static com.oracle.truffle.r.library.stats.DPQ.rd0;
+import static com.oracle.truffle.r.library.stats.DPQ.rd1;
+import static com.oracle.truffle.r.library.stats.DPQ.rdexp;
+import static com.oracle.truffle.r.library.stats.DPQ.rdfexp;
+import static com.oracle.truffle.r.library.stats.DPQ.rdt0;
+import static com.oracle.truffle.r.library.stats.DPQ.rdt1;
+import static com.oracle.truffle.r.library.stats.DPQ.rdtclog;
+import static com.oracle.truffle.r.library.stats.DPQ.rdtqiv;
+import static com.oracle.truffle.r.library.stats.DPQ.rlog1exp;
+import static com.oracle.truffle.r.library.stats.MathConstants.DBL_EPSILON;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_1_SQRT_2PI;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_2PI;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_LN2;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_SQRT_32;
+import static com.oracle.truffle.r.library.stats.RMath.fmax2;
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_1;
 import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_2;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -62,6 +59,13 @@ public abstract class GammaFunctions {
         }
     }
 
+    public static final class DGamma implements Function3_1 {
+        @Override
+        public double evaluate(double x, double shape, double scale, boolean giveLog) {
+            return dgamma(x, shape, scale, giveLog);
+        }
+    }
+
     // The remainder of this file is derived from GNU R (mostly nmath): qgamma.c, nmath.h, lgamma.c,
     // gamma.c, stirlerr.c, lgammacor.c, pgamma.c, fmax2.c, dpois.c, bd0.c, dgamma.c, pnorm.c,
     // qnorm.c
@@ -178,7 +182,7 @@ public abstract class GammaFunctions {
             /* allow to underflow below */
         } else if (x < xbig) {
             tmp = 10 / x;
-            return chebyshevEval(tmp * tmp * 2 - 1, ALGMCS, nalgm) / x;
+            return RMath.chebyshevEval(tmp * tmp * 2 - 1, ALGMCS, nalgm) / x;
         }
         return 1 / (x * 12);
     }
@@ -249,7 +253,7 @@ public abstract class GammaFunctions {
             }
             y = x - n; /* n = floor(x) ==> y in [ 0, 1 ) */
             --n;
-            value = chebyshevEval(y * 2 - 1, GAMCS, ngam) + .9375;
+            value = RMath.chebyshevEval(y * 2 - 1, GAMCS, ngam) + .9375;
             if (n == 0) {
                 return value; /* x = 1.dddd = 1+y */
             }
@@ -367,7 +371,7 @@ public abstract class GammaFunctions {
         }
 
         if (x <= 0 && x == (long) x) { /* Negative integer argument */
-            RError.warning(RError.SHOW_CALLER2, RError.Message.VALUE_OUT_OF_RANGE, "lgamma");
+            RError.warning(RError.SHOW_CALLER, RError.Message.VALUE_OUT_OF_RANGE, "lgamma");
             return Double.POSITIVE_INFINITY; /* +Inf, since lgamma(x) = log|gamma(x)| */
         }
 
@@ -384,7 +388,7 @@ public abstract class GammaFunctions {
          */
 
         if (y > gfn_sign_xmax) {
-            RError.warning(RError.SHOW_CALLER2, RError.Message.VALUE_OUT_OF_RANGE, "lgamma");
+            RError.warning(RError.SHOW_CALLER, RError.Message.VALUE_OUT_OF_RANGE, "lgamma");
             return Double.POSITIVE_INFINITY;
         }
 
@@ -453,9 +457,10 @@ public abstract class GammaFunctions {
             return p + nu;
         }
 
-        if (rqp01check(p, logp)) {
-            // TODO ML_ERR_return_NAN
-            return Double.NaN;
+        try {
+            DPQ.rqp01check(p, logp);
+        } catch (EarlyReturn e) {
+            return e.result;
         }
 
         if (nu <= 0) {
@@ -466,7 +471,7 @@ public abstract class GammaFunctions {
         alpha = 0.5 * nu; /* = [pq]gamma() shape */
         c = alpha - 1;
 
-        if (nu < (-1.24) * (p1 = rdtlog(p, lowerTail, logp))) { /* for small chi-squared */
+        if (nu < (-1.24) * (p1 = DPQ.rdtlog(p, lowerTail, logp))) { /* for small chi-squared */
             /*
              * log(alpha) + g = log(alpha) + log(gamma(alpha)) = = log(alpha*gamma(alpha)) =
              * lgamma(alpha+1) suffers from catastrophic cancellation when alpha << 1
@@ -769,7 +774,7 @@ public abstract class GammaFunctions {
     /* Accurate calculation of log(1+x)-x, particularly for small x. */
     private static double log1pmx(double x) {
         if (x > 1 || x < minLog1Value) {
-            return log1p(x) - x;
+            return RMath.log1p(x) - x;
         } else { /*
                   * -.791 <= x <= 1 -- expand in [x/(2+x)]^2 =: y : log(1+x) - x = x/(2+x) * [ 2 * y
                   * * S(y) - x], with --------------------------------------------- S(y) = 1/3 + y/5
@@ -831,7 +836,7 @@ public abstract class GammaFunctions {
     } /* lgamma1p */
 
     /* If |x| > |k| * M_cutoff, then log[ exp(-x) * k^x ] =~= -x */
-    private static final double M_cutoff = M_LN2 * Double.MAX_EXPONENT / DBLEPSILON;
+    private static final double M_cutoff = M_LN2 * Double.MAX_EXPONENT / DBL_EPSILON;
 
     /*
      * dpois_wrap (x_P_1, lambda, g_log) == dpois (x_P_1 - 1, lambda, g_log) := exp(-L) L^k /
@@ -871,10 +876,10 @@ public abstract class GammaFunctions {
             c *= -x / n;
             term = c / (alph + n);
             sum += term;
-        } while (Math.abs(term) > DBLEPSILON * Math.abs(sum));
+        } while (Math.abs(term) > DBL_EPSILON * Math.abs(sum));
 
         if (lowerTail) {
-            double f1 = logp ? log1p(sum) : 1 + sum;
+            double f1 = logp ? RMath.log1p(sum) : 1 + sum;
             double f2;
             if (alph > 1) {
                 f2 = dpoisRaw(alph, x, logp);
@@ -888,10 +893,10 @@ public abstract class GammaFunctions {
         } else {
             double lf2 = alph * Math.log(x) - lgamma1p(alph);
             if (logp) {
-                return rlog1exp(log1p(sum) + lf2);
+                return rlog1exp(RMath.log1p(sum) + lf2);
             } else {
                 double f1m1 = sum;
-                double f2m1 = expm1(lf2);
+                double f2m1 = RMath.expm1(lf2);
                 return -(f1m1 + f2m1 + f1m1 * f2m1);
             }
         }
@@ -906,7 +911,7 @@ public abstract class GammaFunctions {
             localY++;
             term *= x / localY;
             sum += term;
-        } while (term > sum * DBLEPSILON);
+        } while (term > sum * DBL_EPSILON);
 
         /*
          * sum = \sum_{n=1}^ oo x^n / (y*(y+1)*...*(y+n-1)) = \sum_{n=0}^ oo x^(n+1) /
@@ -948,7 +953,7 @@ public abstract class GammaFunctions {
 
         f0 = y / d;
         /* Needed, e.g. for pgamma(10^c(100,295), shape= 1.1, log=TRUE): */
-        if (Math.abs(y - 1) < Math.abs(d) * DBLEPSILON) { /* includes y < d = Inf */
+        if (Math.abs(y - 1) < Math.abs(d) * DBL_EPSILON) { /* includes y < d = Inf */
             return f0;
         }
 
@@ -999,7 +1004,7 @@ public abstract class GammaFunctions {
             if (b2 != 0) {
                 f = a2 / b2;
                 /* convergence check: relative; "absolute" for very small f : */
-                if (Math.abs(f - of) <= DBLEPSILON * fmax2(f0, Math.abs(f))) {
+                if (Math.abs(f - of) <= DBL_EPSILON * fmax2(f0, Math.abs(f))) {
                     return f;
                 }
                 of = f;
@@ -1015,7 +1020,7 @@ public abstract class GammaFunctions {
         double term = 1;
         double sum = 0;
 
-        while (localY >= 1 && term > sum * DBLEPSILON) {
+        while (localY >= 1 && term > sum * DBL_EPSILON) {
             term *= localY / lambda;
             sum += term;
             localY--;
@@ -1076,7 +1081,7 @@ public abstract class GammaFunctions {
                 term *= -i / x2;
                 sum += term;
                 i += 2;
-            } while (Math.abs(term) > DBLEPSILON * sum);
+            } while (Math.abs(term) > DBL_EPSILON * sum);
 
             return 1 / sum;
         } else {
@@ -1154,7 +1159,7 @@ public abstract class GammaFunctions {
 
         if (logp) {
             double ndOverP = dpnorm(s2pt, !lowerTail, np);
-            return np + log1p(f * ndOverP);
+            return np + RMath.log1p(f * ndOverP);
         } else {
             double nd = dnorm(s2pt, 0., 1., logp);
             return np + f * nd;
@@ -1190,7 +1195,7 @@ public abstract class GammaFunctions {
             double sum;
             double d = dpoisWrap(alph, x, logp);
             if (alph < 1) {
-                if (x * DBLEPSILON > 1 - alph) {
+                if (x * DBL_EPSILON > 1 - alph) {
                     sum = rd1(logp);
                 } else {
                     double f = pdLowerCf(alph, x - (alph - 1)) * x / alph;
@@ -1199,7 +1204,7 @@ public abstract class GammaFunctions {
                 }
             } else {
                 sum = pdLowerSeries(x, alph - 1); /* = (alph-1)/x + o((alph-1)/x) */
-                sum = logp ? log1p(sum) : 1 + sum;
+                sum = logp ? RMath.log1p(sum) : 1 + sum;
             }
             if (!lowerTail) {
                 res = logp ? sum + d : sum * d;
@@ -1214,7 +1219,7 @@ public abstract class GammaFunctions {
          * We lose a fair amount of accuracy to underflow in the cases where the final result is
          * very close to DBL_MIN. In those cases, simply redo via log space.
          */
-        if (!logp && res < Double.MIN_VALUE / DBLEPSILON) {
+        if (!logp && res < Double.MIN_VALUE / DBL_EPSILON) {
             /* with(.Machine, double.xmin / double.eps) #|-> 1.002084e-292 */
             return Math.exp(pgammaRaw(x, alph, lowerTail, true));
         } else {
@@ -1246,7 +1251,7 @@ public abstract class GammaFunctions {
     // dpois
     //
 
-    private static double dpoisRaw(double x, double lambda, boolean giveLog) {
+    public static double dpoisRaw(double x, double lambda, boolean giveLog) {
         /*
          * x >= 0 ; integer for dpois(), but not e.g. for pgamma()! lambda >= 0
          */
@@ -1306,7 +1311,7 @@ public abstract class GammaFunctions {
     // dnorm
     //
 
-    private static double dnorm(double x, double mu, double sigma, boolean giveLog) {
+    static double dnorm(double x, double mu, double sigma, boolean giveLog) {
         double localX = x;
         if (Double.isNaN(localX) || Double.isNaN(mu) || Double.isNaN(sigma)) {
             return localX + mu + sigma;
@@ -1338,7 +1343,7 @@ public abstract class GammaFunctions {
     // dgamma
     //
 
-    private static double dgamma(double x, double shape, double scale, boolean giveLog) {
+    public static double dgamma(double x, double shape, double scale, boolean giveLog) {
         double pr;
         if (Double.isNaN(x) || Double.isNaN(shape) || Double.isNaN(scale)) {
             return x + shape + scale;
@@ -1431,7 +1436,7 @@ public abstract class GammaFunctions {
         if (logp) {
             cum[0] = (-xsq * xsq * 0.5) + (-del * 0.5) + Math.log(temp);
             if ((lower && x > 0.) || (upper && x <= 0.)) {
-                ccum[0] = log1p(-Math.exp(-xsq * xsq * 0.5) * Math.exp(-del * 0.5) * temp);
+                ccum[0] = RMath.log1p(-Math.exp(-xsq * xsq * 0.5) * Math.exp(-del * 0.5) * temp);
             }
         } else {
             cum[0] = Math.exp(-xsq * xsq * 0.5) * Math.exp(-del * 0.5) * temp;
@@ -1472,7 +1477,7 @@ public abstract class GammaFunctions {
         }
 
         /* Consider changing these : */
-        eps = DBLEPSILON * 0.5;
+        eps = DBL_EPSILON * 0.5;
 
         /* i_tail in {0,1,2} =^= {lower, upper, both} */
         lower = iTail != 1;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Geom.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Geom.java
new file mode 100644
index 0000000000000000000000000000000000000000..2d9c81f9f15d5b506cc803b3adabdd34cf30ade5
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Geom.java
@@ -0,0 +1,99 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 1998--2008, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 2000--2014, The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+/*
+ * Copyright (C) 1998       Ross Ihaka
+ * Copyright (C) 2000-12    The R Core Team
+ * Copyright (C) 2004--2005 The R Foundation
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ */
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.MathConstants.forceint;
+
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction1_Double;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_1;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function2_2;
+
+public class Geom {
+    public static final class QGeom implements Function2_2 {
+        @Override
+        public double evaluate(double p, double prob, boolean lowerTail, boolean logP) {
+            if (prob <= 0 || prob > 1) {
+                return RMath.mlError();
+            }
+
+            try {
+                DPQ.rqp01boundaries(p, 0, Double.POSITIVE_INFINITY, lowerTail, logP);
+            } catch (EarlyReturn e) {
+                return e.result;
+            }
+
+            if (Double.isNaN(p) || Double.isNaN(prob)) {
+                return p + prob;
+            }
+
+            if (prob == 1) {
+                return 0;
+            }
+            /* add a fuzz to ensure left continuity, but value must be >= 0 */
+            return RMath.fmax2(0, Math.ceil(DPQ.rdtclog(p, lowerTail, logP) / RMath.log1p(-prob) - 1 - 1e-12));
+        }
+
+    }
+
+    public static final class DGeom implements Function2_1 {
+        @Override
+        public double evaluate(double x, double p, boolean giveLog) {
+            if (Double.isNaN(x) || Double.isNaN(p)) {
+                return x + p;
+            }
+            if (p <= 0 || p > 1) {
+                return RMath.mlError();
+            }
+
+            try {
+                DPQ.nonintCheck(x, giveLog);
+            } catch (EarlyReturn e) {
+                return e.result;
+            }
+
+            if (x < 0 || !Double.isFinite(x) || p == 0) {
+                return DPQ.rd0(giveLog);
+            }
+            /* prob = (1-p)^x, stable for small p */
+            double prob = Dbinom.dbinomRaw(0., forceint(x), p, 1 - p, giveLog);
+            return ((giveLog) ? Math.log(p) + prob : p * prob);
+        }
+    }
+
+    public static final class RGeom implements RandFunction1_Double {
+        @Override
+        public double evaluate(double p, RandomNumberProvider rand) {
+            if (!Double.isFinite(p) || p <= 0 || p > 1) {
+                return RMath.mlError();
+            }
+            return RPois.rpois(rand.expRand() * ((1 - p) / p), rand);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LBeta.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LBeta.java
index 6cc0de5a33d977f8dec7d56bf66456d975a15ee3..8f997c3f586187da864b6cb32346d7ea03826c01 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LBeta.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LBeta.java
@@ -38,7 +38,7 @@ public final class LBeta {
 
         /* both arguments must be >= 0 */
         if (p < 0) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         } else if (p == 0) {
             return Double.POSITIVE_INFINITY;
         } else if (!Double.isFinite(q)) { /* q == +Inf */
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LogNormal.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LogNormal.java
new file mode 100644
index 0000000000000000000000000000000000000000..824a4acef8f241ac6d5d34f358f970ce727e15a7
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LogNormal.java
@@ -0,0 +1,95 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 2000--2014, The R Core Team
+ * Copyright (c) 2005, The R Foundation
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_1;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_2;
+
+public final class LogNormal {
+    private LogNormal() {
+        // only static members
+    }
+
+    public static final class RLNorm implements RandFunction2_Double {
+        private final Rnorm rnorm = new Rnorm();
+
+        @Override
+        public double evaluate(double meanlog, double sdlog, RandomNumberProvider rand) {
+            if (Double.isNaN(meanlog) || !Double.isFinite(sdlog) || sdlog < 0.) {
+                return RMath.mlError();
+            }
+            return Math.exp(rnorm.evaluate(meanlog, sdlog, rand));
+        }
+    }
+
+    public static final class DLNorm implements Function3_1 {
+        @Override
+        public double evaluate(double x, double meanlog, double sdlog, boolean giveLog) {
+            if (Double.isNaN(x) || Double.isNaN(meanlog) || Double.isNaN(sdlog)) {
+                return x + meanlog + sdlog;
+            }
+            if (sdlog <= 0) {
+                if (sdlog < 0) {
+                    return RMath.mlError();
+                }
+                // sdlog == 0 :
+                return (Math.log(x) == meanlog) ? Double.POSITIVE_INFINITY : DPQ.rd0(giveLog);
+            }
+            if (x <= 0) {
+                return DPQ.rd0(giveLog);
+            }
+
+            double y = (Math.log(x) - meanlog) / sdlog;
+            return (giveLog ? -(MathConstants.M_LN_SQRT_2PI + 0.5 * y * y + Math.log(x * sdlog)) : MathConstants.M_1_SQRT_2PI * Math.exp(-0.5 * y * y) / (x * sdlog));
+            /* M_1_SQRT_2PI = 1 / Math.sqrt(2 * pi) */
+        }
+    }
+
+    public static final class QLNorm implements Function3_2 {
+        private final Qnorm qnorm = new Qnorm();
+
+        @Override
+        public double evaluate(double p, double meanlog, double sdlog, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(p) || Double.isNaN(meanlog) || Double.isNaN(sdlog)) {
+                return p + meanlog + sdlog;
+            }
+            try {
+                DPQ.rqp01boundaries(p, 0, Double.POSITIVE_INFINITY, lowerTail, logP);
+            } catch (EarlyReturn e) {
+                return e.result;
+            }
+            return Math.exp(qnorm.evaluate(p, meanlog, sdlog, lowerTail, logP));
+        }
+    }
+
+    public static final class PLNorm implements Function3_2 {
+        private final Pnorm pnorm = new Pnorm();
+
+        @Override
+        public double evaluate(double x, double meanlog, double sdlog, boolean lowerTail, boolean logP) {
+            if (Double.isNaN(x) || Double.isNaN(meanlog) || Double.isNaN(sdlog)) {
+                return x + meanlog + sdlog;
+            }
+            if (sdlog < 0) {
+                return RMath.mlError();
+            }
+            if (x > 0) {
+                return pnorm.evaluate(Math.log(x), meanlog, sdlog, lowerTail, logP);
+            }
+            return DPQ.rdt0(lowerTail, logP);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/MathConstants.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/MathConstants.java
index 1fbefb2a995f10460e01aef039b2ad94135b163c..0885fbeecf503bb056f1c289b3c2096f5ef3e5a3 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/MathConstants.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/MathConstants.java
@@ -3,9 +3,10 @@
  * Version 2. You may review the terms of this license at
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
- * Copyright (c) 1995-2012, The R Core Team
- * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 1998--2012, The R Core Team
+ * Copyright (c) 2004, The R Foundation
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -55,7 +56,7 @@ public final class MathConstants {
     // 1/sqrt(2)
     public static final double M_SQRT1_2 = 0.707106781186547524400844362105;
 
-    /* R-Specific Constants */
+    /* R-Specific Constants from dpq.h and Rmath.h and others */
     // sqrt(3)
     public static final double M_SQRT_3 = 1.732050807568877293527446341506;
     // sqrt(32)
@@ -77,6 +78,12 @@ public final class MathConstants {
     // log(sqrt(pi/2)) == log(pi/2)/2
     public static final double M_LN_SQRT_PId2 = 0.225791352644727432363097614947;
 
+    public static final double DBL_MANT_DIG = 53;
+
+    public static final int DBL_MAX_EXP = 1024;
+
+    public static final int DBL_MIN_EXP = -1021;
+
     public static final double DBL_EPSILON = Math.ulp(1.0);
 
     /**
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbeta.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbeta.java
index 4c950e6d35727e6fc3511907fc7f621500f399af..02c713c68abadf8fe6755b5a2ead937269cc88bd 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbeta.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbeta.java
@@ -12,14 +12,21 @@ package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.library.stats.StatsFunctions.Function3_2;
 import com.oracle.truffle.r.library.stats.TOMS708.Bratio;
-import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 
 // transcribed from pbeta.c
 
-public abstract class Pbeta extends RExternalBuiltinNode.Arg5 {
+public final class Pbeta implements Function3_2 {
+
+    private final BranchProfile naProfile = BranchProfile.create();
+
+    @Override
+    public double evaluate(double x, double a, double b, boolean lowerTail, boolean logP) {
+        return pbeta(x, a, b, lowerTail, logP, naProfile);
+    }
 
     @TruffleBoundary
     private static double pbetaRaw(double x, double a, double b, boolean lowerTail, boolean logProb) {
@@ -32,19 +39,19 @@ public abstract class Pbeta extends RExternalBuiltinNode.Arg5 {
             }
             if (a == 0 || a / b == 0) {
                 // point mass 1 at 0 ==> P(X <= x) = 1, all x > 0
-                return DPQ.dt1(logProb, lowerTail);
+                return DPQ.rdt1(lowerTail, logProb);
             }
             if (b == 0 || b / a == 0) {
                 // point mass 1 at 1 ==> P(X <= x) = 0, all x < 1
-                return DPQ.dt0(logProb, lowerTail);
+                return DPQ.rdt0(lowerTail, logProb);
             }
 
             // else, remaining case: a = b = Inf : point mass 1 at 1/2
             if (x < 0.5) {
-                return DPQ.dt0(logProb, lowerTail);
+                return DPQ.rdt0(lowerTail, logProb);
             }
             // else, x >= 0.5 :
-            return DPQ.dt1(logProb, lowerTail);
+            return DPQ.rdt1(lowerTail, logProb);
         }
         // Now: 0 < a < Inf; 0 < b < Inf
 
@@ -77,10 +84,10 @@ public abstract class Pbeta extends RExternalBuiltinNode.Arg5 {
         // allowing a==0 and b==0 <==> treat as one- or two-point mass
 
         if (x <= 0) {
-            return DPQ.dt0(logP, lowerTail);
+            return DPQ.rdt0(lowerTail, logP);
         }
         if (x >= 1) {
-            return DPQ.dt1(logP, lowerTail);
+            return DPQ.rdt1(lowerTail, logP);
         }
 
         return pbetaRaw(x, a, b, lowerTail, logP);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbinom.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbinom.java
index 2885a3c8b596d50c426db8664de8559088826846..70fcce282db80d30395effba2881a35c155aafcb 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbinom.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pbinom.java
@@ -13,7 +13,6 @@
 package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.runtime.RError;
 
 public final class Pbinom implements StatsFunctions.Function3_2 {
 
@@ -34,8 +33,8 @@ public final class Pbinom implements StatsFunctions.Function3_2 {
 
         if (DPQ.nonint(size)) {
             nanProfile.enter();
-            RError.warning(RError.SHOW_CALLER, RError.Message.NON_INTEGER_N, "n", size);
-            return Double.NaN;
+            DPQ.nointCheckWarning(size, "n");
+            return DPQ.rd0(logP);
         }
         size = Math.round(size);
         /* PR#8560: n=0 is a valid value */
@@ -45,11 +44,11 @@ public final class Pbinom implements StatsFunctions.Function3_2 {
         }
 
         if (q < 0) {
-            return DPQ.dt0(logP, lowerTail);
+            return DPQ.rdt0(lowerTail, logP);
         }
         q = Math.floor(q + 1e-7);
         if (size <= q) {
-            return DPQ.dt1(logP, lowerTail);
+            return DPQ.rdt1(lowerTail, logP);
         }
         return Pbeta.pbeta(prob, q + 1, size - q, !lowerTail, logP, nanProfile);
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pf.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pf.java
index 51cf4f7e06d1f2833ce943b59dc2296041260add..f595cf1cc339e26326e79c2d9ebe5d3984e182cf 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pf.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pf.java
@@ -11,7 +11,8 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import static com.oracle.truffle.r.library.stats.StatsUtil.*;
+import static com.oracle.truffle.r.library.stats.DPQ.rdt0;
+import static com.oracle.truffle.r.library.stats.DPQ.rdt1;
 
 import com.oracle.truffle.api.profiles.BranchProfile;
 
@@ -45,7 +46,7 @@ public final class Pf implements StatsFunctions.Function3_2 {
                     return rdt0(lowerTail, logP);
                 }
                 if (x == 1) {
-                    return logP ? -M_LN2 : 0.5;
+                    return logP ? -MathConstants.M_LN2 : 0.5;
                 }
                 if (x > 1) {
                     return rdt1(lowerTail, logP);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pnorm.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pnorm.java
index bae5a546448f141bb8a75e4f012792e19b7fe32b..2d73851c472337e07e46861bed2700d4ccb9a2d2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pnorm.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Pnorm.java
@@ -41,11 +41,11 @@ public final class Pnorm implements StatsFunctions.Function3_2 {
                 return Double.NaN;
             }
             /* sigma = 0 : */
-            return (x < mu) ? DPQ.d0(logP) : DPQ.d1(logP);
+            return (x < mu) ? DPQ.rdt0(lowerTail, logP) : DPQ.rdt1(lowerTail, logP);
         }
         double p = (x - mu) / sigma;
         if (!Double.isFinite(p)) {
-            return (x < mu) ? DPQ.d0(logP) : DPQ.d1(logP);
+            return (x < mu) ? DPQ.rdt0(lowerTail, logP) : DPQ.rdt1(lowerTail, logP);
         }
 
         PnormBoth pnormBoth = new PnormBoth(p);
@@ -204,11 +204,11 @@ public final class Pnorm implements StatsFunctions.Function3_2 {
                 swapTail(x, lower);
             } else { /* large x such that probs are 0 or 1 */
                 if (x > 0) {
-                    cum = DPQ.d1(logP);
-                    ccum = DPQ.d0(logP);
+                    cum = DPQ.rd1(logP);
+                    ccum = DPQ.rd0(logP);
                 } else {
-                    cum = DPQ.d0(logP);
-                    ccum = DPQ.d1(logP);
+                    cum = DPQ.rd0(logP);
+                    ccum = DPQ.rd1(logP);
                 }
             }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/QHyper.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/QHyper.java
index d3e23b0e73276ac48c384b17a182ec639278afcb..c3a43d3259eba623afcabfc64774ea901a893bbf 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/QHyper.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/QHyper.java
@@ -13,9 +13,9 @@ package com.oracle.truffle.r.library.stats;
 
 import static com.oracle.truffle.r.library.stats.MathConstants.DBL_EPSILON;
 import static com.oracle.truffle.r.library.stats.MathConstants.forceint;
-import static com.oracle.truffle.r.library.stats.StatsUtil.fmax2;
-import static com.oracle.truffle.r.library.stats.StatsUtil.fmin2;
-import static com.oracle.truffle.r.library.stats.StatsUtil.lfastchoose;
+import static com.oracle.truffle.r.library.stats.RMath.fmax2;
+import static com.oracle.truffle.r.library.stats.RMath.fmin2;
+import static com.oracle.truffle.r.library.stats.RMath.lfastchoose;
 
 import com.oracle.truffle.r.library.stats.DPQ.EarlyReturn;
 
@@ -34,7 +34,7 @@ public final class QHyper {
             return p + nr + nb + n;
         }
         if (!Double.isFinite(p) || !Double.isFinite(nr) || !Double.isFinite(nb) || !Double.isFinite(n)) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         nr = forceint(nr);
@@ -42,7 +42,7 @@ public final class QHyper {
         capN = nr + nb;
         n = forceint(n);
         if (nr < 0 || nb < 0 || n < 0 || n > capN) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         /*
@@ -54,7 +54,7 @@ public final class QHyper {
         xend = fmin2(n, nr);
 
         try {
-            DPQ.qP01Boundaries(p, xstart, xend, lowerTail, logP);
+            DPQ.rqp01boundaries(p, xstart, xend, lowerTail, logP);
         } catch (EarlyReturn ex) {
             return ex.result;
         }
@@ -75,7 +75,7 @@ public final class QHyper {
         nb -= xb;
 
         if (!lowerTail || logP) {
-            p = DPQ.dtQIv(p, lowerTail, logP);
+            p = DPQ.rdtqiv(p, lowerTail, logP);
         }
         p *= 1 - 1000 * DBL_EPSILON; /* was 64, but failed on FreeBSD sometimes */
         sum = smallN ? term : Math.exp(term);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qbinom.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qbinom.java
index 6bab507fdc59415010679410aaf6d0cdabfcb6c9..32e4f1df57df5f8f87b110d4cdef6dff2ae41402 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qbinom.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qbinom.java
@@ -126,7 +126,7 @@ public final class Qbinom implements StatsFunctions.Function3_2 {
          * [cancellation for p ~= 1, etc]:
          */
         if (!lowerTail || logProb) {
-            p = DPQ.dtQIv(p, lowerTail, logProb); /* need check again (cancellation!): */
+            p = DPQ.rdtqiv(p, lowerTail, logProb); /* need check again (cancellation!): */
             if (p == 0) {
                 return 0;
             }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qnorm.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qnorm.java
index 73dc865c65ef8d64be9ea18e57f867475d5e3a9d..42efb456233e808e5f0119665e833637675143b1 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qnorm.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Qnorm.java
@@ -31,7 +31,7 @@ public final class Qnorm implements StatsFunctions.Function3_2 {
             return p + mu + sigma;
         }
         try {
-            DPQ.qP01Boundaries(p, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, lowerTail, logP);
+            DPQ.rqp01boundaries(p, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, lowerTail, logP);
         } catch (EarlyReturn early) {
             return early.result;
         }
@@ -44,7 +44,7 @@ public final class Qnorm implements StatsFunctions.Function3_2 {
             return mu;
         }
 
-        double p2 = DPQ.dtQIv(p, lowerTail, logP); /* real lower_tail prob. p */
+        double p2 = DPQ.rdtqiv(p, lowerTail, logP); /* real lower_tail prob. p */
         double q = p2 - 0.5;
 
         debugPrintf("qnorm(p=%10.7g, m=%g, s=%g, l.t.= %d, log= %d): q = %g\n", p, mu, sigma, lowerTail, logP, q);
@@ -76,7 +76,7 @@ public final class Qnorm implements StatsFunctions.Function3_2 {
             /* r = min(p, 1-p) < 0.075 */
             double r;
             if (q > 0) {
-                r = DPQ.dtCIv(p, lowerTail, logP); /* 1-p */
+                r = DPQ.rdtciv(p, lowerTail, logP); /* 1-p */
             } else {
                 r = p2; /* = R_DT_Iv(p) ^= p */
             }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java
index 9ba8e64a12ac14fa2575067e12d4dc4b878b8eec..d62ab89e7e74c7d8962352525c10588f022e4c2d 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java
@@ -12,10 +12,10 @@
  */
 package com.oracle.truffle.r.library.stats;
 
+import static com.oracle.truffle.r.library.stats.MathConstants.DBL_MAX_EXP;
 import static com.oracle.truffle.r.library.stats.MathConstants.M_LN2;
-import static com.oracle.truffle.r.library.stats.StatsUtil.DBL_MAX_EXP;
-import static com.oracle.truffle.r.library.stats.StatsUtil.fmax2;
-import static com.oracle.truffle.r.library.stats.StatsUtil.fmin2;
+import static com.oracle.truffle.r.library.stats.RMath.fmax2;
+import static com.oracle.truffle.r.library.stats.RMath.fmin2;
 
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
@@ -27,7 +27,7 @@ public final class RBeta implements RandFunction2_Double {
     @Override
     public double evaluate(double aa, double bb, RandomNumberProvider rand) {
         if (Double.isNaN(aa) || Double.isNaN(bb) || aa < 0. || bb < 0.) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         if (!Double.isFinite(aa) && !Double.isFinite(bb)) { // a = b = Inf : all mass at 1/2
             return 0.5;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java
deleted file mode 100644
index accf46e7c246e8914ab9075568984edbe7194507..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (C) 1998 Ross Ihaka
- * Copyright (c) 1998--2008, The R Core Team
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-package com.oracle.truffle.r.library.stats;
-
-import static com.oracle.truffle.r.library.stats.MathConstants.M_PI;
-
-import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
-import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
-
-public final class RCauchy implements RandFunction2_Double {
-    @Override
-    public double evaluate(double location, double scale, RandomNumberProvider rand) {
-        if (Double.isNaN(location) || !Double.isFinite(scale) || scale < 0) {
-            return StatsUtil.mlError();
-        }
-        if (scale == 0. || !Double.isFinite(location)) {
-            return location;
-        } else {
-            return location + scale * Math.tan(M_PI * rand.unifRand());
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RChisq.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RChisq.java
index 3b4c21ac102e287b7f0c21c0fdd01a6dd7eff473..67ba496753caf017b672e0003654a11f1eb4904d 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RChisq.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RChisq.java
@@ -17,7 +17,7 @@ import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberPr
 public final class RChisq implements RandFunction1_Double {
     public static double rchisq(double df, RandomNumberProvider rand) {
         if (!Double.isFinite(df) || df < 0.0) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         return new RGamma().evaluate(df / 2.0, 2.0, rand);
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RExp.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RExp.java
deleted file mode 100644
index 078f113dc20a407979ce7f75e2eb634ac663ea82..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RExp.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (C) 1998 Ross Ihaka
- * Copyright (c) 1998--2008, The R Core Team
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-package com.oracle.truffle.r.library.stats;
-
-import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction1_Double;
-import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
-
-public final class RExp implements RandFunction1_Double {
-    @Override
-    public double evaluate(double scale, RandomNumberProvider rand) {
-        if (!Double.isFinite(scale) || scale <= 0.0) {
-            return scale == 0. ? 0. : StatsUtil.mlError();
-        }
-        return scale * rand.expRand();
-    }
-}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java
index 0e8581b5035469b7af5bc26d512b224447bf5dfd..eea9b5aea8027a913db009a0f96260fa22327fed 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java
@@ -66,13 +66,13 @@ public class RGamma implements RandFunction2_Double {
         double retVal;
 
         if (Double.isNaN(a) || Double.isNaN(scale)) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         if (a <= 0.0 || scale <= 0.0) {
             if (scale == 0. || a == 0.) {
                 return 0.;
             }
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         if (!Double.isFinite(a) || !Double.isFinite(scale)) {
             return Double.POSITIVE_INFINITY;
@@ -192,7 +192,7 @@ public class RGamma implements RandFunction2_Double {
                 /* Step 11: hat acceptance (h) */
                 /* (if q not positive go to step 8) */
                 if (q > 0.0) {
-                    w = StatsUtil.expm1(q);
+                    w = RMath.expm1(q);
                     /* ^^^^^ original code had approximation with rel.err < 2e-7 */
                     /* if t is rejected sample again at step 8 */
                     if (c * fabs(u) <= w * Math.exp(e - 0.5 * t * t)) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGeom.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGeom.java
deleted file mode 100644
index 555d703a529b0e2021bf70e6ac116b93cdcd9467..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGeom.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (C) 1998 Ross Ihaka
- * Copyright (c) 1998--2008, The R Core Team
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-package com.oracle.truffle.r.library.stats;
-
-import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction1_Double;
-import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
-
-public final class RGeom implements RandFunction1_Double {
-    @Override
-    public double evaluate(double p, RandomNumberProvider rand) {
-        if (!Double.isFinite(p) || p <= 0 || p > 1) {
-            return StatsUtil.mlError();
-        }
-        return RPois.rpois(rand.expRand() * ((1 - p) / p), rand);
-    }
-}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RHyper.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RHyper.java
index 32d9c6afee1cdf69754660e0d751057aefd13389..7dba16badee221972e01340629a88e35ffe0a1b1 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RHyper.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RHyper.java
@@ -100,7 +100,7 @@ public final class RHyper implements RandFunction3_Double {
         /* check parameter validity */
 
         if (!Double.isFinite(nn1in) || !Double.isFinite(nn2in) || !Double.isFinite(kkin)) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         nn1in = forceint(nn1in);
@@ -108,7 +108,7 @@ public final class RHyper implements RandFunction3_Double {
         kkin = forceint(kkin);
 
         if (nn1in < 0 || nn2in < 0 || kkin < 0 || kkin > nn1in + nn2in) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         if (nn1in >= Integer.MAX_VALUE || nn2in >= Integer.MAX_VALUE || kkin >= Integer.MAX_VALUE) {
             /*
@@ -230,7 +230,7 @@ public final class RHyper implements RandFunction3_Double {
                 nUv++;
                 if (nUv >= 10000) {
                     RError.warning(RError.SHOW_CALLER, Message.GENERIC, String.format("rhyper() branch III: giving up after %d rejections", nUv));
-                    return StatsUtil.mlError();
+                    return RMath.mlError();
                 }
 
                 if (u < p1) { /* rectangular region */
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RLogis.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RLogis.java
index 007b812f841e234635bf6880d12728f879add390..961dafe00d10a34156926a5b54379f5510e45ebc 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RLogis.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RLogis.java
@@ -18,7 +18,7 @@ public final class RLogis implements RandFunction2_Double {
     @Override
     public double evaluate(double location, double scale, RandomNumberProvider rand) {
         if (Double.isNaN(location) || !Double.isFinite(scale)) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         if (scale == 0. || !Double.isFinite(location)) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMath.java
similarity index 66%
rename from com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java
rename to com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMath.java
index 7a5348110e6dcddb2b05578952f40a334ac2f354..7b0d2a4c0dc0e158da8cfad77148cfff9c3028fe 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMath.java
@@ -16,12 +16,15 @@ import static com.oracle.truffle.r.library.stats.LBeta.lbeta;
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.runtime.RRuntime;
 
 /**
- * Auxiliary functions and constants from GNU R. These are originally found in the source files
- * mentioned in the code.
+ * Encapsulates functions to be found in Rmath.h or in nmath directory in GnuR except for random
+ * distribution related functions, which usually have their own files.
+ *
+ * @see DPQ
  */
-public class StatsUtil {
+public class RMath {
 
     /**
      * corresponds to macro {@code ML_ERR_return_NAN} in GnuR.
@@ -30,97 +33,6 @@ public class StatsUtil {
         return Double.NaN;
     }
 
-    public static final double DBLEPSILON = 2.2204460492503131e-16;
-
-    @TruffleBoundary
-    private static void fail(String message) {
-        throw new RuntimeException(message);
-    }
-
-    // Constants and auxiliary functions originate from dpq.h and Rmath.h.
-
-    public static final double M_LN2 = 0.693147180559945309417232121458;
-
-    public static final double M_PI = 3.141592653589793238462643383280;
-
-    public static final double M_2PI = 6.283185307179586476925286766559;
-
-    public static final double M_1_SQRT_2PI = 0.398942280401432677939946059934;
-
-    public static final double M_SQRT_32 = 5.656854249492380195206754896838;
-
-    public static final double M_LOG10_2 = 0.301029995663981195213738894724;
-
-    public static final double DBL_MANT_DIG = 53;
-
-    public static final int DBL_MAX_EXP = 1024;
-
-    public static final int DBL_MIN_EXP = -1021;
-
-    public static double rdtlog(double p, boolean lowerTail, boolean logp) {
-        return lowerTail ? rdlog(p, logp) : rdlexp(p, logp);
-    }
-
-    public static double rdlog(double p, boolean logp) {
-        return logp ? p : Math.log(p);
-    }
-
-    public static double rdlexp(double x, boolean logp) {
-        return logp ? rlog1exp(x) : log1p(-x);
-    }
-
-    public static double rlog1exp(double x) {
-        return x > -M_LN2 ? Math.log(-expm1(x)) : log1p(-Math.exp(x));
-    }
-
-    public static double rdtclog(double p, boolean lowerTail, boolean logp) {
-        return lowerTail ? rdlexp(p, logp) : rdlog(p, logp);
-    }
-
-    public static double rdtqiv(double p, boolean lowerTail, boolean logp) {
-        return logp ? (lowerTail ? Math.exp(p) : -expm1(p)) : rdlval(p, lowerTail);
-    }
-
-    public static double rdtciv(double p, boolean lowerTail, boolean logp) {
-        return logp ? (lowerTail ? -expm1(p) : Math.exp(p)) : rdcval(p, lowerTail);
-    }
-
-    public static double rdlval(double p, boolean lowerTail) {
-        return lowerTail ? p : (0.5 - (p) + 0.5);
-    }
-
-    public static double rdcval(double p, boolean lowerTail) {
-        return lowerTail ? (0.5 - p + 0.5) : p;
-    }
-
-    public static double rd0(boolean logp) {
-        return logp ? Double.NEGATIVE_INFINITY : 0.;
-    }
-
-    public static double rd1(boolean logp) {
-        return logp ? 0. : 1.;
-    }
-
-    public static double rdt0(boolean lowerTail, boolean logp) {
-        return lowerTail ? rd0(logp) : rd1(logp);
-    }
-
-    public static double rdt1(boolean lowerTail, boolean logp) {
-        return lowerTail ? rd1(logp) : rd0(logp);
-    }
-
-    public static boolean rqp01check(double p, boolean logp) {
-        return (logp && p > 0) || (!logp && (p < 0 || p > 1));
-    }
-
-    public static double rdexp(double x, boolean logp) {
-        return logp ? x : Math.exp(x);
-    }
-
-    public static double rdfexp(double f, double x, boolean giveLog) {
-        return giveLog ? -0.5 * Math.log(f) + x : Math.exp(x) / Math.sqrt(f);
-    }
-
     public static double lfastchoose(double n, double k) {
         return -Math.log(n + 1.) - lbeta(n - k + 1., k + 1.);
     }
@@ -132,6 +44,38 @@ public class StatsUtil {
         return ((y >= 0) ? TOMS708.fabs(x) : -TOMS708.fabs(x));
     }
 
+    public static double fmod(double a, double b) {
+        double q = a / b;
+        if (b != 0) {
+            double tmp = a - Math.floor(q) * b;
+            if (RRuntime.isFinite(q) && Math.abs(q) > 1 / RRuntime.EPSILON) {
+                // TODO support warning here
+                throw new UnsupportedOperationException();
+            }
+            return tmp - Math.floor(tmp / b) * b;
+        } else {
+            return Double.NaN;
+        }
+    }
+
+    public static double tanpi(double x) {
+        if (Double.isNaN(x)) {
+            return x;
+        }
+        if (!Double.isFinite(x)) {
+            return mlError();
+        }
+
+        x = fmod(x, 1.); // tan(pi(x + k)) == tan(pi x) for all integer k
+        // map (-1,1) --> (-1/2, 1/2] :
+        if (x <= -0.5) {
+            x++;
+        } else if (x > 0.5) {
+            x--;
+        }
+        return (x == 0.) ? 0. : ((x == 0.5) ? Double.NaN : Math.tan(MathConstants.M_PI * x));
+    }
+
     //
     // GNUR from fmin2.c and fmax2
     //
@@ -158,7 +102,7 @@ public class StatsUtil {
         double y;
         double a = Math.abs(x);
 
-        if (a < DBLEPSILON) {
+        if (a < MathConstants.DBL_EPSILON) {
             return x;
         }
         if (a > 0.697) {
@@ -173,7 +117,7 @@ public class StatsUtil {
         }
         /* Newton step for solving log(1 + y) = x for y : */
         /* WARNING: does not work for y ~ -1: bug in 1.5.0 */
-        y -= (1 + y) * (log1p(y) - x);
+        y -= (1 + y) * (RMath.log1p(y) - x);
         return y;
     }
 
@@ -216,7 +160,7 @@ public class StatsUtil {
             /*
              * Improve on speed (only); again give result accurate to IEEE double precision:
              */
-            if (Math.abs(x) < .5 * DBLEPSILON) {
+            if (Math.abs(x) < .5 * MathConstants.DBL_EPSILON) {
                 return x;
             }
 
@@ -263,4 +207,9 @@ public class StatsUtil {
         }
         return (b0 - b2) * 0.5;
     }
+
+    @TruffleBoundary
+    private static void fail(String message) {
+        throw new RuntimeException(message);
+    }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNbinomMu.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNbinomMu.java
index bac788a88f092635d86a66edb0f39d218c08f813..c095616fa14e46565ba778fbf3356a6f257ddc66 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNbinomMu.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNbinomMu.java
@@ -20,7 +20,7 @@ public final class RNbinomMu implements RandFunction2_Double {
     @Override
     public double evaluate(double size, double mu, RandomNumberProvider rand) {
         if (!Double.isFinite(mu) || Double.isNaN(size) || size <= 0 || mu < 0) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         if (!Double.isFinite(size)) {
             size = Double.MAX_VALUE / 2.;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNchisq.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNchisq.java
index da55025e1ad1d072053cd34ce4dab98b98260a8e..5e22bda3f5faf7e3fd655ed596183d3df56e6c07 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNchisq.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNchisq.java
@@ -22,7 +22,7 @@ public final class RNchisq implements RandFunction2_Double {
     @Override
     public double evaluate(double df, double lambda, RandomNumberProvider rand) {
         if (!Double.isFinite(df) || !Double.isFinite(lambda) || df < 0. || lambda < 0.) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         if (lambda == 0.) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RPois.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RPois.java
index ffcc999eace1ce6645b72423f3a7ee81f7cbb191..2638fa34de84ce1797d21b9e75acdb4798ab2ba5 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RPois.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RPois.java
@@ -80,7 +80,7 @@ public final class RPois implements RandFunction1_Double {
         boolean newBigMu = false;
 
         if (!Double.isFinite(mu) || mu < 0) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         if (mu <= 0.) {
@@ -219,7 +219,7 @@ public final class RPois implements RandFunction1_Double {
                  * sample t from the laplace 'hat' (if t <= -0.6744 then pk < fk for all mu >= 10.)
                  */
                 u = 2 * rand.unifRand() - 1.;
-                t = 1.8 + StatsUtil.fsign(e, u);
+                t = 1.8 + RMath.fsign(e, u);
             }
 
             if (t > -0.6744 || gotoStepF) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RWeibull.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RWeibull.java
index 6e1fae2faf3211f4352d2dfae59e4a0a95c3c0d7..3686f96591d283d05747f0a49deb6dbb5b4c1b93 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RWeibull.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RWeibull.java
@@ -18,7 +18,7 @@ public final class RWeibull implements RandFunction2_Double {
     @Override
     public double evaluate(double shape, double scale, RandomNumberProvider rand) {
         if (!Double.isFinite(shape) || !Double.isFinite(scale) || shape <= 0. || scale <= 0.) {
-            return scale == 0. ? 0. : StatsUtil.mlError();
+            return scale == 0. ? 0. : RMath.mlError();
         }
 
         return scale * Math.pow(-Math.log(rand.unifRand()), 1.0 / shape);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Random2.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Random2.java
index e81ed75ed1f546923c664cb7c2d214909e9f0471..729f0d0833ed777de42e12fc552206ce7d12f58d 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Random2.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Random2.java
@@ -11,8 +11,8 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdtciv;
-import static com.oracle.truffle.r.library.stats.StatsUtil.rdtqiv;
+import static com.oracle.truffle.r.library.stats.DPQ.rdtciv;
+import static com.oracle.truffle.r.library.stats.DPQ.rdtqiv;
 
 /*
  * Logic derived from GNU-R, see inline comments.
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rf.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rf.java
index 5d9426797321df6200e4dbc4a00eb9c9e551cb87..21cbb6d2bcf8609018f0fa730b73c6f59f0c8892 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rf.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rf.java
@@ -18,7 +18,7 @@ public final class Rf implements RandFunction2_Double {
     @Override
     public double evaluate(double n1, double n2, RandomNumberProvider rand) {
         if (Double.isNaN(n1) || Double.isNaN(n2) || n1 <= 0. || n2 <= 0.) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         double v1;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java
index 24f2aed7d53b9d6f82635bec1bb53b441f4daa9b..1996274e87ea2c9c733dfdf4ad7ff06cb2eb0270 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java
@@ -18,7 +18,7 @@ public final class Rnorm implements RandFunction2_Double {
     @Override
     public double evaluate(double mu, double sigma, RandomNumberProvider rand) {
         if (Double.isNaN(mu) || !Double.isFinite(sigma) || sigma < 0.) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         if (sigma == 0. || !Double.isFinite(mu)) {
             return mu; /* includes mu = +/- Inf with finite sigma */
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rt.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rt.java
index 2ba6a6271371c136fe6a29a544797de96be0513f..51a266499e2e0af2b8c120ff15edcc26ae123310 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rt.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rt.java
@@ -20,7 +20,7 @@ public final class Rt implements RandFunction1_Double {
     @Override
     public double evaluate(double df, RandomNumberProvider rand) {
         if (Double.isNaN(df) || df <= 0.0) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
 
         if (!Double.isFinite(df)) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java
index 57a877536fa532404eb5899b115ba11e4c812043..5701011cf53f8e9f6ee09cae6e6294696b393de8 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java
@@ -30,7 +30,7 @@ public final class Runif implements RandFunction2_Double {
     @Override
     public double evaluate(double min, double max, RandomNumberProvider rand) {
         if (!RRuntime.isFinite(min) || !RRuntime.isFinite(max) || max < min) {
-            return StatsUtil.mlError();
+            return RMath.mlError();
         }
         if (min == max) {
             return min;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Signrank.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Signrank.java
index 422d76cb6f7c006a3e94ad3779e76fc6d9cfb0b2..1b33cb4ddb8d4aeac8960ed8a69100feefeec1e2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Signrank.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Signrank.java
@@ -31,12 +31,12 @@ public final class Signrank {
             if (Double.isInfinite(n)) {
                 // In GnuR these "results" seem to be generated due to the behaviour of R_forceint,
                 // and the "(int) n" cast, which ends up casting +/-infinity to integer...
-                return n < 0 ? StatsUtil.mlError() : 0;
+                return n < 0 ? RMath.mlError() : 0;
             }
 
             n = forceint(n);
             if (n < 0) {
-                return StatsUtil.mlError();
+                return RMath.mlError();
             }
 
             if (n == 0) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java
index 0f78a1f32eeb141cbe6370b9e7c4cde94bb49a3e..80d764515eef04f25d408662217f208623651a3e 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java
@@ -43,6 +43,7 @@ public class SplineFunctions {
     }
 
     public abstract static class SplineEval extends RExternalBuiltinNode.Arg2 {
+        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
 
         @Specialization
         @TruffleBoundary
@@ -90,7 +91,7 @@ public class SplineFunctions {
     /*
      * Periodic Spline --------------- The end conditions here match spline (and its derivatives) at
      * x[1] and x[n].
-     * 
+     *
      * Note: There is an explicit check that the user has supplied data with y[1] equal to y[n].
      */
     private static void periodicSpline(int n, double[] x, double[] y, double[] b, double[] c, double[] d) {
@@ -207,7 +208,7 @@ public class SplineFunctions {
     /*
      * Natural Splines --------------- Here the end-conditions are determined by setting the second
      * derivative of the spline at the end-points to equal to zero.
-     * 
+     *
      * There are n-2 unknowns (y[i]'' at x[2], ..., x[n-1]) and n-2 equations to determine them.
      * Either Choleski or Gaussian elimination could be used.
      */
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctions.java
index ec49eda23c9b8ba99c2717648e5a5a3595d99f59..48c80044ba8a6b2d181a9f1e1b15564d5e66b66b 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctions.java
@@ -14,6 +14,7 @@ package com.oracle.truffle.r.library.stats;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
@@ -27,6 +28,7 @@ import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -36,6 +38,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 // inspired by arithmetic.c
 
 public final class StatsFunctions {
+    @CompilationFinal private static final RDouble DUMMY_VECTOR = RDouble.valueOf(1);
+
     private StatsFunctions() {
         // private
     }
@@ -53,6 +57,24 @@ public final class StatsFunctions {
         double evaluate(double a, double b, double c, boolean x);
     }
 
+    public interface Function2_1 extends Function3_2 {
+        @Override
+        default double evaluate(double a, double b, double c, boolean x, boolean y) {
+            return evaluate(a, b, x);
+        }
+
+        double evaluate(double a, double b, boolean x);
+    }
+
+    public interface Function2_2 extends Function3_2 {
+        @Override
+        default double evaluate(double a, double b, double c, boolean x, boolean y) {
+            return evaluate(a, b, x, y);
+        }
+
+        double evaluate(double a, double b, boolean x, boolean y);
+    }
+
     static final class StatFunctionProfiles {
         final BranchProfile nan = BranchProfile.create();
         final NACheck aCheck = NACheck.create();
@@ -86,6 +108,7 @@ public final class StatsFunctions {
         profiles.aCheck.enable(a);
         profiles.bCheck.enable(b);
         profiles.cCheck.enable(c);
+        profiles.loopConditionProfile.profileCounted(length);
         for (int i = 0; profiles.loopConditionProfile.inject(i < length); i++) {
             double aValue = a.getDataAt(i % aLength);
             double bValue = b.getDataAt(i % bLength);
@@ -150,7 +173,7 @@ public final class StatsFunctions {
     }
 
     public abstract static class Function3_1Node extends RExternalBuiltinNode.Arg4 {
-        private final Function3_2 function;
+        private final Function3_1 function;
 
         public Function3_1Node(Function3_1 function) {
             this.function = function;
@@ -172,6 +195,51 @@ public final class StatsFunctions {
         }
     }
 
+    public abstract static class Function2_1Node extends RExternalBuiltinNode.Arg3 {
+        private final Function2_1 function;
+
+        public Function2_1Node(Function2_1 function) {
+            this.function = function;
+        }
+
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg(0).asDoubleVector();
+            casts.arg(1).asDoubleVector();
+            casts.arg(2).asLogicalVector().findFirst().map(toBoolean());
+        }
+
+        @Specialization
+        protected RAbstractDoubleVector evaluate(RAbstractDoubleVector a, RAbstractDoubleVector b, boolean x,
+                        @Cached("create()") StatFunctionProfiles profiles,
+                        @Cached("create()") UnaryCopyAttributesNode copyAttributesNode) {
+            return evaluate3(this, function, a, b, DUMMY_VECTOR, x, false /* dummy */, profiles, copyAttributesNode);
+        }
+    }
+
+    public abstract static class Function2_2Node extends RExternalBuiltinNode.Arg4 {
+        private final Function2_2 function;
+
+        public Function2_2Node(Function2_2 function) {
+            this.function = function;
+        }
+
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg(0).asDoubleVector();
+            casts.arg(1).asDoubleVector();
+            casts.arg(2).asLogicalVector().findFirst().map(toBoolean());
+            casts.arg(3).asLogicalVector().findFirst().map(toBoolean());
+        }
+
+        @Specialization
+        protected RAbstractDoubleVector evaluate(RAbstractDoubleVector a, RAbstractDoubleVector b, boolean x, boolean y,
+                        @Cached("create()") StatFunctionProfiles profiles,
+                        @Cached("create()") UnaryCopyAttributesNode copyAttributesNode) {
+            return evaluate3(this, function, a, b, DUMMY_VECTOR, x, y, profiles, copyAttributesNode);
+        }
+    }
+
     public abstract static class ApproxTest extends RExternalBuiltinNode.Arg4 {
         @Override
         protected void createCasts(CastBuilder casts) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java
index a61e44b42201c5c5af425fa83c95fd84718d8e8f..65056493bd7f7358f33beff9b9ef16afa8141c67 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java
@@ -177,8 +177,8 @@ public class TOMS708 {
             eps = RRuntime.EPSILON; /* == DBL_EPSILON (in R, Rmath) */
 
             /* ----------------------------------------------------------------------- */
-            w = DPQ.d0(logP);
-            w1 = DPQ.d0(logP);
+            w = DPQ.rd0(logP);
+            w1 = DPQ.rd0(logP);
 
             if (a < 0.0 || b < 0.0) {
                 return result(w, w1, 1);
@@ -206,8 +206,8 @@ public class TOMS708 {
                     return result(w, w1, 6);
                 }
                 // else:
-                w = DPQ.d0(logP);
-                w1 = DPQ.d1(logP);
+                w = DPQ.rd0(logP);
+                w1 = DPQ.rd1(logP);
                 return result(w, w1, 0);
             }
             if (y == 0.0) {
@@ -215,20 +215,20 @@ public class TOMS708 {
                     return result(w, w1, 7);
                 }
                 // else:
-                w = DPQ.d1(logP);
-                w1 = DPQ.d0(logP);
+                w = DPQ.rd1(logP);
+                w1 = DPQ.rd0(logP);
                 return result(w, w1, 0);
             }
 
             if (a == 0.0) {
                 // else:
-                w = DPQ.d1(logP);
-                w1 = DPQ.d0(logP);
+                w = DPQ.rd1(logP);
+                w1 = DPQ.rd0(logP);
                 return result(w, w1, 0);
             }
             if (b == 0.0) {
-                w = DPQ.d0(logP);
-                w1 = DPQ.d1(logP);
+                w = DPQ.rd0(logP);
+                w1 = DPQ.rd1(logP);
                 return result(w, w1, 0);
             }
 
@@ -762,7 +762,7 @@ public class TOMS708 {
          */
 
         if (x == 0.) {
-            return DPQ.d0(logP);
+            return DPQ.rd0(logP);
         }
         /* ----------------------------------------------------------------------- */
         /* compute the factor x^a/(a*Beta(a,b)) */
@@ -850,7 +850,7 @@ public class TOMS708 {
             }
         }
         debugPrintf(" bpser(a=%f, b=%f, x=%f, log=%b): prelim.ans = %.14f;\n", a, b, x, logP, ans);
-        if (ans == DPQ.d0(logP) || (!logP && a <= eps * 0.1)) {
+        if (ans == DPQ.rd0(logP) || (!logP && a <= eps * 0.1)) {
             return ans;
         }
 
@@ -1059,7 +1059,7 @@ public class TOMS708 {
         /* R has M_1_SQRT_2PI , and M_LN_SQRT_2PI = ln(sqrt(2*pi)) = 0.918938.. */
 
         if (x == 0.0 || y == 0.0) {
-            return DPQ.d0(logP);
+            return DPQ.rd0(logP);
         }
         double a0 = min(a, b);
         if (a0 < 8.0) {
@@ -1081,7 +1081,7 @@ public class TOMS708 {
             double z = a * lnx + b * lny;
             if (a0 >= 1.) {
                 z -= betaln(a, b);
-                return DPQ.dExp(z, logP);
+                return DPQ.rdexp(z, logP);
             }
 
             /* ----------------------------------------------------------------------- */
@@ -1098,7 +1098,7 @@ public class TOMS708 {
 
             if (b0 <= 1.0) { /* algorithm for max(a,b) = b0 <= 1 */
 
-                double eZ = DPQ.dExp(z, logP);
+                double eZ = DPQ.rdexp(z, logP);
 
                 if (!logP && eZ == 0.0) {
                     /* exp() underflow */
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java
index e793668a8a24f91d57eb57e120592cb04b223961..d1ca9be10dc5ac29f642f8960f8e0c504341cff1 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/C_ParseRd.java
@@ -37,8 +37,10 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
 
 public abstract class C_ParseRd extends RExternalBuiltinNode.Arg9 {
+    @Child ToolsRFFI.ToolsRFFINode toolsRFFINode = RFFIFactory.getRFFI().getToolsRFFI().createToolsRFFINode();
 
     @Override
     protected void createCasts(CastBuilder casts) {
@@ -64,7 +66,7 @@ public abstract class C_ParseRd extends RExternalBuiltinNode.Arg9 {
 
         try (RConnection openConn = RConnection.fromIndex(con).forceOpen("r")) {
             // @formatter:off
-            return RFFIFactory.getRFFI().getToolsRFFI().parseRd(openConn, srcfile,
+            return toolsRFFINode.parseRd(openConn, srcfile,
                             RDataFactory.createLogicalVectorFromScalar(verboseL),
                             RDataFactory.createLogicalVectorFromScalar(fragmentL),
                             RDataFactory.createStringVectorFromScalar(basename.getDataAt(0)),
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
index e856fd478387c79b96ea48c676b782656aa248d3..49204b765ddbc5dee540d31c69888ec6a8c857f2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
 import java.util.TreeSet;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -37,6 +38,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
 
+    @Child private SetFixedAttributeNode setLevelsAttrNode = SetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
+
     private static boolean isNA(String s, RAbstractStringVector naStrings) {
         // naStrings are in addition to NA_character_
         if (RRuntime.isNA(s)) {
@@ -178,7 +181,7 @@ public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
                 }
             }
             RIntVector res = RDataFactory.createIntVector(data, complete);
-            res.setAttr(RRuntime.LEVELS_ATTR_KEY, RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
+            setLevelsAttrNode.execute(res, RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
             return RVector.setVectorClassAttr(res, RDataFactory.createStringVector("factor"));
         }
     }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Parse.c b/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
index cc55518f197af736df1fedfb4780aea80643c0c4..233a58dbc129066a73b9a1cb364bc7cffde33b1a 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
@@ -30,15 +30,15 @@ static jfieldID parseExprFieldID;
 
 
 void init_parse(JNIEnv *env) {
-	parseMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ParseVector", "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;", 1);
-	parseResultClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper$ParseResult");
+	parseMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ParseVector", "(Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;", 0);
+	parseResultClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/ParseResult");
 	parseStatusFieldID = checkGetFieldID(env, parseResultClass, "parseStatus", "I", 0);
 	parseExprFieldID = checkGetFieldID(env, parseResultClass, "expr", "Ljava/lang/Object;", 0);
 }
 
 SEXP R_ParseVector(SEXP text, int n, ParseStatus *z, SEXP srcfile) {
 	JNIEnv *env = getEnv();
-	jobject result = (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, parseMethodID, text, n, srcfile);
+	jobject result = (*env)->CallObjectMethod(env, UpCallsRFFIObject, parseMethodID, text, n, srcfile);
 	*z = (*env)->GetIntField(env, result, parseStatusFieldID);
     return (*env)->GetObjectField(env, result, parseExprFieldID);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Random.c b/com.oracle.truffle.r.native/fficall/src/jni/Random.c
index 70341f309a7db4277f773e630c336e597bbfa1e7..4c958521f14747b05fe32b15575b49b1026a53bb 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Random.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Random.c
@@ -27,24 +27,24 @@ static jmethodID PutRNGstate_MethodID;
 static jmethodID UnifRand_MethodID;
 
 void init_random(JNIEnv *env) {
-	GetRNGstate_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "getRNGstate", "()V", 1);
-	PutRNGstate_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "putRNGstate", "()V", 1);
-	UnifRand_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "unifRand", "()D", 1);
+	GetRNGstate_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "GetRNGstate", "()V", 0);
+	PutRNGstate_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "PutRNGstate", "()V", 0);
+	UnifRand_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "unif_rand", "()D", 0);
 }
 
 void GetRNGstate() {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, GetRNGstate_MethodID);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, GetRNGstate_MethodID);
 }
 
 void PutRNGstate() {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, PutRNGstate_MethodID);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, PutRNGstate_MethodID);
 }
 
 double unif_rand() {
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticDoubleMethod(thisenv, CallRFFIHelperClass, UnifRand_MethodID);
+	return (*thisenv)->CallDoubleMethod(thisenv, UpCallsRFFIObject, UnifRand_MethodID);
 }
 
 double norm_rand() {
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
index f7cb4401f5891fd9cfbcf9802c9b52f91c3dc10c..11bfb92d75d0e34e4117a7ad926a9ec098ba92c4 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
@@ -178,8 +178,8 @@ int Rf_initialize_R(int argc, char *argv[]) {
 
 char *R_HomeDir(void) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID R_HomeDirMethodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_HomeDir", "()Ljava/lang/String;", 1);
-	jstring homeDir = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, R_HomeDirMethodID);
+	jmethodID R_HomeDirMethodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_HomeDir", "()Ljava/lang/String;", 0);
+	jstring homeDir = (*jniEnv)->CallObjectMethod(jniEnv, UpCallsRFFIObject, R_HomeDirMethodID);
 	const char *homeDirChars = stringToChars(jniEnv, homeDir);
 	return (char *)homeDirChars;
 }
@@ -308,8 +308,8 @@ void uR_Busy(int x) {
 
 void uR_CleanUp(SA_TYPE x, int y, int z) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_CleanUp", "(III)V", 1);
-	(*jniEnv)->CallStaticVoidMethod(jniEnv, CallRFFIHelperClass, methodID, x, y, z);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_CleanUp", "(III)V", 1);
+	(*jniEnv)->CallStaticVoidMethod(jniEnv, UpCallsRFFIClass, methodID, x, y, z);
 }
 
 int uR_ShowFiles(int a, const char **b, const char **c,
@@ -599,63 +599,63 @@ static char **update_environ_with_java_home(void) {
 
 CTXT R_getGlobalFunctionContext() {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getGlobalFunctionContext", "()Ljava/lang/Object;", 1);
-    CTXT result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_getGlobalFunctionContext", "()Ljava/lang/Object;", 0);
+    CTXT result = (*jniEnv)->CallObjectMethod(jniEnv, UpCallsRFFIObject, methodID);
     SEXP new_result = checkRef(jniEnv, result);
     return new_result == R_NilValue ? NULL : addGlobalRef(jniEnv, result, 0);
 }
 
 CTXT R_getParentFunctionContext(CTXT c) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getParentFunctionContext", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-    CTXT result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, c);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_getParentFunctionContext", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+    CTXT result = (*jniEnv)->CallObjectMethod(jniEnv, UpCallsRFFIObject, methodID, c);
     SEXP new_result = checkRef(jniEnv, result);
     return new_result == R_NilValue ? NULL : addGlobalRef(jniEnv, result, 0);
 }
 
 SEXP R_getContextEnv(CTXT context) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextEnv", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_getContextEnv", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+    SEXP result = (*jniEnv)->CallObjectMethod(jniEnv, UpCallsRFFIObject, methodID, context);
     return checkRef(jniEnv, result);
 }
 
 SEXP R_getContextFun(CTXT context) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextFun", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_getContextFun", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+    SEXP result = (*jniEnv)->CallObjectMethod(jniEnv, UpCallsRFFIObject, methodID, context);
     return checkRef(jniEnv, result);
 }
 
 SEXP R_getContextCall(CTXT context) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextCall", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_getContextCall", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+    SEXP result = (*jniEnv)->CallObjectMethod(jniEnv, UpCallsRFFIObject, methodID, context);
     return checkRef(jniEnv, result);
 }
 
 SEXP R_getContextSrcRef(CTXT context) {
     JNIEnv *jniEnv = getEnv();
-    jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getContextSrcRef", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-    SEXP result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+    jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_getContextSrcRef", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+    SEXP result = (*jniEnv)->CallObjectMethod(jniEnv, UpCallsRFFIObject, methodID, context);
     result = checkRef(jniEnv, result);
     return result == R_NilValue ? NULL : result;
 }
 
 int R_insideBrowser() {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_insideBrowser", "()I", 1);
-    return (*jniEnv)->CallStaticIntMethod(jniEnv, CallRFFIHelperClass, methodID);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_insideBrowser", "()I", 0);
+    return (*jniEnv)->CallStaticIntMethod(jniEnv, UpCallsRFFIClass, methodID);
 }
 
 int R_isGlobal(CTXT context) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_isGlobal", "(Ljava/lang/Object;)I", 1);
-    return (*jniEnv)->CallStaticIntMethod(jniEnv, CallRFFIHelperClass, methodID, context);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_isGlobal", "(Ljava/lang/Object;)I", 0);
+    return (*jniEnv)->CallStaticIntMethod(jniEnv, UpCallsRFFIClass, methodID, context);
 }
 
 int R_isEqual(void* x, void* y) {
 	JNIEnv *jniEnv = getEnv();
-	jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_isEqual", "(Ljava/lang/Object;Ljava/lang/Object;)I", 1);
-    return (*jniEnv)->CallStaticIntMethod(jniEnv, CallRFFIHelperClass, methodID, x, y);
+	jmethodID methodID = checkGetMethodID(jniEnv, UpCallsRFFIClass, "R_isEqual", "(Ljava/lang/Object;Ljava/lang/Object;)I", 0);
+    return (*jniEnv)->CallStaticIntMethod(jniEnv, UpCallsRFFIClass, methodID, x, y);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
index 3972ae97f451a894d5e79a20b95c3e47276496b6..540621ad1600f0694ab8c21c598f3fbe7efd6dcf 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -30,7 +30,7 @@
 // to ensure that a global JNI handle is created (if necessary) and returned,
 // otherwise a GC might reclaim the result.
 
-// N.B. ALL functions go via CallRFFIHelper to provide a single point of re-entry
+// N.B. ALL functions go via UpCallsRFFI to provide a single point of re-entry
 
 static jmethodID Rf_ScalarIntegerMethodID;
 static jmethodID Rf_ScalarDoubleMethodID;
@@ -102,7 +102,7 @@ static jmethodID TYPEOF_MethodID;
 static jmethodID OBJECT_MethodID;
 static jmethodID DUPLICATE_ATTRIB_MethodID;
 static jmethodID isS4ObjectMethodID;
-static jmethodID logObject_MethodID;
+static jmethodID logNotCharSXPWrapperMethodID;
 static jmethodID R_tryEvalMethodID;
 static jmethodID RDEBUGMethodID;
 static jmethodID SET_RDEBUGMethodID;
@@ -113,7 +113,7 @@ static jmethodID PRVALUEMethodID;
 static jmethodID R_lsInternal3MethodID;
 static jmethodID R_do_MAKE_CLASS_MethodID;
 
-static jmethodID resetAndGetHandlerStacksMethodID;
+static jmethodID R_ToplevelExecMethodID;
 static jmethodID restoreHandlerStacksMethodID;
 
 static jmethodID R_MakeExternalPtrMethodID;
@@ -136,107 +136,107 @@ static jfieldID CharSXPWrapperContentsFieldID;
 jmethodID setCompleteMethodID;
 
 void init_internals(JNIEnv *env) {
-	Rf_ScalarIntegerMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_ScalarInteger", "(I)Lcom/oracle/truffle/r/runtime/data/RIntVector;", 1);
-	Rf_ScalarDoubleMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_ScalarDouble", "(D)Lcom/oracle/truffle/r/runtime/data/RDoubleVector;", 1);
-	Rf_ScalarStringMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_ScalarString", "(Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RStringVector;", 1);
-	Rf_ScalarLogicalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_ScalarLogical", "(I)Lcom/oracle/truffle/r/runtime/data/RLogicalVector;", 1);
-	Rf_consMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_cons", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_evalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_eval", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_findfunMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_findfun", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_defineVarMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_defineVar", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 1);
-	Rf_findVarMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_findVar", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_findVarInFrameMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_findVarInFrame", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_findVarInFrame3MethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_findVarInFrame3", "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/Object;", 1);
-	Rf_getAttribMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_getAttrib", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_setAttribMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_setAttrib", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 1);
-	Rf_isStringMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_isString", "(Ljava/lang/Object;)I", 1);
-	Rf_isNullMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_isNull", "(Ljava/lang/Object;)I", 1);
-	Rf_installMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_install", "(Ljava/lang/String;)Ljava/lang/Object;", 1);
-	Rf_warningMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_warning", "(Ljava/lang/String;)V", 1);
-	Rf_warningcallMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_warningcall", "(Ljava/lang/Object;Ljava/lang/String;)V", 1);
-	Rf_errorMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_error", "(Ljava/lang/String;)V", 1);
-	Rf_allocateVectorMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_allocateVector", "(II)Ljava/lang/Object;", 1);
-	Rf_allocateMatrixMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_allocateMatrix", "(III)Ljava/lang/Object;", 1);
-	Rf_allocateArrayMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_allocateArray", "(ILjava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_duplicateMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_duplicate", "(Ljava/lang/Object;I)Ljava/lang/Object;", 1);
-	Rf_anyDuplicatedMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_anyDuplicated", "(Ljava/lang/Object;I)I", 1);
-	R_NewHashedEnvMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;Ljava/lang/String;ZI)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 1);
-	Rf_classgetsMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_classgets", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	RprintfMethodID = checkGetMethodID(env, CallRFFIHelperClass, "printf", "(Ljava/lang/String;)V", 1);
-	R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_do_MAKE_CLASS", "(Ljava/lang/String;)Ljava/lang/Object;", 1);
-	R_FindNamespaceMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_FindNamespace", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	R_BindingIsLockedID = checkGetMethodID(env, CallRFFIHelperClass, "R_BindingIsLocked", "(Ljava/lang/Object;Ljava/lang/Object;)I", 1);
-	Rf_GetOption1MethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_GetOption1", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_gsetVarMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_gsetVar", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 1);
-	Rf_inheritsMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_inherits", "(Ljava/lang/Object;Ljava/lang/String;)I", 1);
-	Rf_lengthgetsMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_lengthgets", "(Ljava/lang/Object;I)Ljava/lang/Object;", 1);
-//	Rf_rPsortMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_rPsort", "(Lcom/oracle/truffle/r/runtime/data/RDoubleVector;II)", 1);
-//	Rf_iPsortMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_iPsort", "(Lcom/oracle/truffle/r/runtime/data/RIntVector;II)", 1);
-	CADR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "CADR", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	CADDR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "CADDR", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	TAG_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "TAG", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	PRINTNAME_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "PRINTNAME", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	CAR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "CAR", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	CDR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "CDR", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	CDDR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "CDDR", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	SET_TAG_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_TAG", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	SETCAR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SETCAR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	SETCDR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SETCDR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	SETCADR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SETCADR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	SYMVALUE_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SYMVALUE", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	SET_SYMVALUE_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_SYMVALUE", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
-	SET_STRING_ELT_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_STRING_ELT", "(Ljava/lang/Object;ILjava/lang/Object;)V", 1);
-	SET_VECTOR_ELT_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_VECTOR_ELT", "(Ljava/lang/Object;ILjava/lang/Object;)V", 1);
-	RAW_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "RAW", "(Ljava/lang/Object;)[B", 1);
-	REAL_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "REAL", "(Ljava/lang/Object;)[D", 1);
-	LOGICAL_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "LOGICAL", "(Ljava/lang/Object;)[B", 1);
-	INTEGER_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "INTEGER", "(Ljava/lang/Object;)[I", 1);
-	STRING_ELT_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "STRING_ELT", "(Ljava/lang/Object;I)Ljava/lang/Object;", 1);
-	VECTOR_ELT_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "VECTOR_ELT", "(Ljava/lang/Object;I)Ljava/lang/Object;", 1);
-	LENGTH_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "LENGTH", "(Ljava/lang/Object;)I", 1);
-	Rf_asIntegerMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_asInteger", "(Ljava/lang/Object;)I", 1);
-//	Rf_asRealMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_asReal", "(Ljava/lang/Object;)D", 1);
-	Rf_asCharMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_asChar", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	Rf_mkCharLenCEMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_mkCharLenCE", "([BI)Ljava/lang/Object;", 1);
-	Rf_asLogicalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_asLogical", "(Ljava/lang/Object;)I", 1);
-	Rf_PairToVectorListMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_PairToVectorList", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	NAMED_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "NAMED", "(Ljava/lang/Object;)I", 1);
-	SET_TYPEOF_FASTR_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_TYPEOF_FASTR", "(Ljava/lang/Object;I)Ljava/lang/Object;", 1);
-	TYPEOF_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "TYPEOF", "(Ljava/lang/Object;)I", 1);
-	OBJECT_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "OBJECT", "(Ljava/lang/Object;)I", 1);
-	DUPLICATE_ATTRIB_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "DUPLICATE_ATTRIB", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
-	isS4ObjectMethodID = checkGetMethodID(env, CallRFFIHelperClass, "isS4Object", "(Ljava/lang/Object;)I", 1);
-	logObject_MethodID = checkGetMethodID(env, CallRFFIHelperClass, "logObject", "(Ljava/lang/Object;)V", 1);
-	R_tryEvalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_tryEval", "(Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;", 1);
-	RDEBUGMethodID = checkGetMethodID(env, CallRFFIHelperClass, "RDEBUG", "(Ljava/lang/Object;)I", 1);
-	SET_RDEBUGMethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_RDEBUG", "(Ljava/lang/Object;I)V", 1);
-	RSTEPMethodID = checkGetMethodID(env, CallRFFIHelperClass, "RSTEP", "(Ljava/lang/Object;)I", 1);
-	SET_RSTEPMethodID = checkGetMethodID(env, CallRFFIHelperClass, "SET_RSTEP", "(Ljava/lang/Object;I)V", 1);
-	ENCLOSMethodID = checkGetMethodID(env, CallRFFIHelperClass, "ENCLOS", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	PRVALUEMethodID = checkGetMethodID(env, CallRFFIHelperClass, "PRVALUE", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	R_lsInternal3MethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_lsInternal3", "(Ljava/lang/Object;II)Ljava/lang/Object;", 1);
-
-	resetAndGetHandlerStacksMethodID = checkGetMethodID(env, CallRFFIHelperClass, "resetAndGetErrorHandlerStacks", "()Ljava/lang/Object;", 1);
-	restoreHandlerStacksMethodID = checkGetMethodID(env, CallRFFIHelperClass, "restoreErrorHandlerStacks", "(Ljava/lang/Object;)V", 1);
-
-	R_MakeExternalPtrMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_MakeExternalPtr", "(JLjava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 1);
-	R_ExternalPtrAddrMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ExternalPtrAddr", "(Ljava/lang/Object;)J", 1);
-	R_ExternalPtrTagMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ExternalPtrTag", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	R_ExternalPtrProtMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_ExternalPtrProt", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
-	R_SetExternalPtrAddrMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_SetExternalPtrAddr", "(Ljava/lang/Object;J)V", 1);
-	R_SetExternalPtrTagMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_SetExternalPtrTag", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
-	R_SetExternalPtrProtMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_SetExternalPtrProt", "(Ljava/lang/Object;Ljava/lang/Object;)V", 1);
-
-	CharSXPWrapperClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper$CharSXPWrapper");
+	Rf_ScalarIntegerMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_ScalarInteger", "(I)Lcom/oracle/truffle/r/runtime/data/RIntVector;", 0);
+	Rf_ScalarDoubleMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_ScalarDouble", "(D)Lcom/oracle/truffle/r/runtime/data/RDoubleVector;", 0);
+	Rf_ScalarStringMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_ScalarString", "(Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RStringVector;", 0);
+	Rf_ScalarLogicalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_ScalarLogical", "(I)Lcom/oracle/truffle/r/runtime/data/RLogicalVector;", 0);
+	Rf_consMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_cons", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_evalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_eval", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_findfunMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_findfun", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_defineVarMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_defineVar", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	Rf_findVarMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_findVar", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_findVarInFrameMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_findVarInFrame", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_findVarInFrame3MethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_findVarInFrame3", "(Ljava/lang/Object;Ljava/lang/Object;I)Ljava/lang/Object;", 0);
+	Rf_getAttribMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_getAttrib", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_setAttribMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_setAttrib", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	Rf_isStringMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_isString", "(Ljava/lang/Object;)I", 0);
+	Rf_isNullMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_isNull", "(Ljava/lang/Object;)I", 0);
+	Rf_installMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_install", "(Ljava/lang/String;)Ljava/lang/Object;", 0);
+	Rf_warningMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warning", "(Ljava/lang/String;)V", 0);
+	Rf_warningcallMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warningcall", "(Ljava/lang/Object;Ljava/lang/String;)V", 0);
+	Rf_errorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_error", "(Ljava/lang/String;)V", 0);
+	Rf_allocateVectorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_allocateVector", "(II)Ljava/lang/Object;", 0);
+	Rf_allocateMatrixMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_allocateMatrix", "(III)Ljava/lang/Object;", 0);
+	Rf_allocateArrayMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_allocateArray", "(ILjava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_duplicateMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_duplicate", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
+	Rf_anyDuplicatedMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_anyDuplicated", "(Ljava/lang/Object;I)I", 0);
+	R_NewHashedEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;Ljava/lang/String;ZI)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 0);
+	Rf_classgetsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_classgets", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	RprintfMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rprintf", "(Ljava/lang/String;)V", 0);
+	R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_MAKE_CLASS", "(Ljava/lang/String;)Ljava/lang/Object;", 0);
+	R_FindNamespaceMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_FindNamespace", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	R_BindingIsLockedID = checkGetMethodID(env, UpCallsRFFIClass, "R_BindingIsLocked", "(Ljava/lang/Object;Ljava/lang/Object;)I", 0);
+	Rf_GetOption1MethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_GetOption1", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_gsetVarMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_gsetVar", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	Rf_inheritsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_inherits", "(Ljava/lang/Object;Ljava/lang/String;)I", 0);
+	Rf_lengthgetsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_lengthgets", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
+//	Rf_rPsortMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_rPsort", "(Lcom/oracle/truffle/r/runtime/data/RDoubleVector;II)", 0);
+//	Rf_iPsortMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_iPsort", "(Lcom/oracle/truffle/r/runtime/data/RIntVector;II)", 0);
+	CADR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "CADR", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	CADDR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "CADDR", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	TAG_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "TAG", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	PRINTNAME_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "PRINTNAME", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	CAR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "CAR", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	CDR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "CDR", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	CDDR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "CDDR", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	SET_TAG_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_TAG", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	SETCAR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SETCAR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	SETCDR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SETCDR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	SETCADR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SETCADR", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	SYMVALUE_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SYMVALUE", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	SET_SYMVALUE_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_SYMVALUE", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	SET_STRING_ELT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_STRING_ELT", "(Ljava/lang/Object;ILjava/lang/Object;)V", 0);
+	SET_VECTOR_ELT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_VECTOR_ELT", "(Ljava/lang/Object;ILjava/lang/Object;)V", 0);
+	RAW_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "RAW", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	REAL_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "REAL", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	LOGICAL_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "LOGICAL", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	INTEGER_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "INTEGER", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	STRING_ELT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "STRING_ELT", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
+	VECTOR_ELT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "VECTOR_ELT", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
+	LENGTH_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "LENGTH", "(Ljava/lang/Object;)I", 0);
+	Rf_asIntegerMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asInteger", "(Ljava/lang/Object;)I", 0);
+//	Rf_asRealMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asReal", "(Ljava/lang/Object;)D", 0);
+	Rf_asCharMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asChar", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_mkCharLenCEMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_mkCharLenCE", "([BI)Ljava/lang/Object;", 0);
+	Rf_asLogicalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asLogical", "(Ljava/lang/Object;)I", 0);
+	Rf_PairToVectorListMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_PairToVectorList", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	NAMED_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "NAMED", "(Ljava/lang/Object;)I", 0);
+	SET_TYPEOF_FASTR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_TYPEOF_FASTR", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0);
+	TYPEOF_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "TYPEOF", "(Ljava/lang/Object;)I", 0);
+	OBJECT_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "OBJECT", "(Ljava/lang/Object;)I", 0);
+	DUPLICATE_ATTRIB_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "DUPLICATE_ATTRIB", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	isS4ObjectMethodID = checkGetMethodID(env, UpCallsRFFIClass, "isS4Object", "(Ljava/lang/Object;)I", 0);
+	logNotCharSXPWrapperMethodID = checkGetMethodID(env, UpCallsRFFIClass, "logNotCharSXPWrapper", "(Ljava/lang/Object;)V", 0);
+	R_tryEvalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_tryEval", "(Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;", 0);
+	RDEBUGMethodID = checkGetMethodID(env, UpCallsRFFIClass, "RDEBUG", "(Ljava/lang/Object;)I", 0);
+	SET_RDEBUGMethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_RDEBUG", "(Ljava/lang/Object;I)V", 0);
+	RSTEPMethodID = checkGetMethodID(env, UpCallsRFFIClass, "RSTEP", "(Ljava/lang/Object;)I", 0);
+	SET_RSTEPMethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_RSTEP", "(Ljava/lang/Object;I)V", 0);
+	ENCLOSMethodID = checkGetMethodID(env, UpCallsRFFIClass, "ENCLOS", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	PRVALUEMethodID = checkGetMethodID(env, UpCallsRFFIClass, "PRVALUE", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	R_lsInternal3MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_lsInternal3", "(Ljava/lang/Object;II)Ljava/lang/Object;", 0);
+
+	R_ToplevelExecMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ToplevelExec", "()Ljava/lang/Object;", 0);
+	restoreHandlerStacksMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ToplevelExecRestoreErrorHandlerStacks", "(Ljava/lang/Object;)V", 0);
+
+	R_MakeExternalPtrMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_MakeExternalPtr", "(JLjava/lang/Object;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/data/RExternalPtr;", 0);
+	R_ExternalPtrAddrMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ExternalPtrAddr", "(Ljava/lang/Object;)J", 0);
+	R_ExternalPtrTagMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ExternalPtrTag", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	R_ExternalPtrProtMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ExternalPtrProt", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	R_SetExternalPtrAddrMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_SetExternalPtrAddr", "(Ljava/lang/Object;J)V", 0);
+	R_SetExternalPtrTagMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_SetExternalPtrTag", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	R_SetExternalPtrProtMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_SetExternalPtrProt", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+
+	CharSXPWrapperClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/CharSXPWrapper");
 	CharSXPWrapperContentsFieldID = checkGetFieldID(env, CharSXPWrapperClass, "contents", "Ljava/lang/String;", 0);
 
-    R_computeIdenticalMethodID = checkGetMethodID(env, CallRFFIHelperClass, "R_computeIdentical", "(Ljava/lang/Object;Ljava/lang/Object;I)I", 1);
-    Rf_copyListMatrixMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_copyListMatrix", "(Ljava/lang/Object;Ljava/lang/Object;I)V", 1);
-    Rf_copyMatrixMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_copyMatrix", "(Ljava/lang/Object;Ljava/lang/Object;I)V", 1);
-    Rf_nrowsMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_nrows", "(Ljava/lang/Object;)I", 1);
-    Rf_ncolsMethodID = checkGetMethodID(env, CallRFFIHelperClass, "Rf_ncols", "(Ljava/lang/Object;)I", 1);
+    R_computeIdenticalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_computeIdentical", "(Ljava/lang/Object;Ljava/lang/Object;I)I", 0);
+    Rf_copyListMatrixMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_copyListMatrix", "(Ljava/lang/Object;Ljava/lang/Object;I)V", 0);
+    Rf_copyMatrixMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_copyMatrix", "(Ljava/lang/Object;Ljava/lang/Object;I)V", 0);
+    Rf_nrowsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_nrows", "(Ljava/lang/Object;)I", 0);
+    Rf_ncolsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_ncols", "(Ljava/lang/Object;)I", 0);
 
-    setCompleteMethodID = checkGetMethodID(env, CallRFFIHelperClass, "setComplete", "(Ljava/lang/Object;Z)V", 1);
+    setCompleteMethodID = checkGetMethodID(env, UpCallsRFFIClass, "setComplete", "(Ljava/lang/Object;Z)V", 0);
 }
 
 static jstring stringFromCharSXP(JNIEnv *thisenv, SEXP charsxp) {
@@ -244,7 +244,7 @@ static jstring stringFromCharSXP(JNIEnv *thisenv, SEXP charsxp) {
 	validateRef(thisenv, charsxp, "stringFromCharSXP");
 	if (!(*thisenv)->IsInstanceOf(thisenv, charsxp, CharSXPWrapperClass)) {
 
-	    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, logObject_MethodID, charsxp);
+	    (*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, logNotCharSXPWrapperMethodID, charsxp);
 	    fatalError("only CharSXPWrapper expected in stringFromCharSXP");
 	}
 #endif
@@ -254,27 +254,27 @@ static jstring stringFromCharSXP(JNIEnv *thisenv, SEXP charsxp) {
 SEXP Rf_ScalarInteger(int value) {
 	TRACE(TARGp, value);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ScalarIntegerMethodID, value);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_ScalarIntegerMethodID, value);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_ScalarReal(double value) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ScalarDoubleMethodID, value);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_ScalarDoubleMethodID, value);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_ScalarString(SEXP value) {
 	TRACE(TARGp, value);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ScalarStringMethodID, value);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_ScalarStringMethodID, value);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_ScalarLogical(int value) {
 	TRACE(TARGp, value);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_ScalarLogicalMethodID, value);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_ScalarLogicalMethodID, value);
     return checkRef(thisenv, result);
 }
 
@@ -285,14 +285,14 @@ SEXP Rf_allocVector3(SEXPTYPE t, R_xlen_t len, R_allocator_t* allocator) {
     }
     TRACE(TARGpd, t, len);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_allocateVectorMethodID, t, len);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_allocateVectorMethodID, t, len);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_allocArray(SEXPTYPE t, SEXP dims) {
 	TRACE(TARGppd, t, dims);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_allocateArrayMethodID, t, dims);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_allocateArrayMethodID, t, dims);
 	return checkRef(thisenv, result);
 }
 
@@ -303,7 +303,7 @@ SEXP Rf_alloc3DArray(SEXPTYPE t, int x, int y, int z) {
 SEXP Rf_allocMatrix(SEXPTYPE mode, int nrow, int ncol) {
 	TRACE(TARGppd, mode, nrow, ncol);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_allocateMatrixMethodID, mode, nrow, ncol);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_allocateMatrixMethodID, mode, nrow, ncol);
 	return checkRef(thisenv, result);
 }
 
@@ -319,14 +319,14 @@ SEXP Rf_allocSExp(SEXPTYPE t) {
 SEXP Rf_cons(SEXP car, SEXP cdr) {
 	TRACE(TARGpp, car, cdr);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_consMethodID, car, cdr);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_consMethodID, car, cdr);
     return checkRef(thisenv, result);
 }
 
 void Rf_defineVar(SEXP symbol, SEXP value, SEXP rho) {
 	TRACE(TARGppp, symbol, value, rho);
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_defineVarMethodID, symbol, value, rho);
+	(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_defineVarMethodID, symbol, value, rho);
 }
 
 void Rf_setVar(SEXP x, SEXP y, SEXP z) {
@@ -345,63 +345,63 @@ SEXP Rf_eval(SEXP expr, SEXP env) {
 	TRACE(TARGpp, expr, env);
     JNIEnv *thisenv = getEnv();
     updateNativeArrays(thisenv);
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_evalMethodID, expr, env);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_evalMethodID, expr, env);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_findFun(SEXP symbol, SEXP rho) {
 	TRACE(TARGpp, symbol, rho);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findfunMethodID, symbol, rho);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_findfunMethodID, symbol, rho);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_findVar(SEXP sym, SEXP rho) {
 	TRACE(TARGpp, sym, rho);
 	JNIEnv *thisenv = getEnv();
-	SEXP result =(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarMethodID, sym, rho);
+	SEXP result =(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_findVarMethodID, sym, rho);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_findVarInFrame(SEXP rho, SEXP sym) {
 	TRACE(TARGpp, rho, sym);
 	JNIEnv *thisenv = getEnv();
-	SEXP result =(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarInFrameMethodID, rho, sym);
+	SEXP result =(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_findVarInFrameMethodID, rho, sym);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_findVarInFrame3(SEXP rho, SEXP sym, Rboolean b) {
 	TRACE(TARGppd, rho, sym, b);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_findVarInFrame3MethodID, rho, sym, b);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_findVarInFrame3MethodID, rho, sym, b);
     return checkRef(thisenv, result);
 }
 
 SEXP Rf_getAttrib(SEXP vec, SEXP name) {
 	TRACE(TARGpp, vec, name);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_getAttribMethodID, vec, name);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_getAttribMethodID, vec, name);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_setAttrib(SEXP vec, SEXP name, SEXP val) {
 	TRACE(TARGppp, vec,name, val);
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, Rf_setAttribMethodID, vec, name, val);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, Rf_setAttribMethodID, vec, name, val);
 	return val;
 }
 
 SEXP Rf_duplicate(SEXP x) {
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_duplicateMethodID, x, 1);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_duplicateMethodID, x, 1);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_shallow_duplicate(SEXP x) {
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_duplicateMethodID, x, 0);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_duplicateMethodID, x, 0);
 	return checkRef(thisenv, result);
 }
 
@@ -409,7 +409,7 @@ R_xlen_t Rf_any_duplicated(SEXP x, Rboolean from_last) {
 	TRACE(TARGpd, x, from_last);
     if (!isVector(x)) error(_("'duplicated' applies only to vectors"));
 	JNIEnv *thisenv = getEnv();
-    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_anyDuplicatedMethodID, x, from_last);
+    return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_anyDuplicatedMethodID, x, from_last);
 }
 
 SEXP Rf_duplicated(SEXP x, Rboolean y) {
@@ -437,7 +437,7 @@ Rboolean Rf_inherits(SEXP x, const char * klass) {
 	TRACE(TARGps, x, klass);
     JNIEnv *thisenv = getEnv();
     jstring klazz = (*thisenv)->NewStringUTF(thisenv, klass);
-    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_inheritsMethodID, x, klazz);
+    return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_inheritsMethodID, x, klazz);
 }
 
 Rboolean Rf_isReal(SEXP x) {
@@ -477,7 +477,7 @@ SEXP Rf_install(const char *name) {
 	TRACE(TARGs, name);
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, name);
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_installMethodID, string);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_installMethodID, string);
 	return checkRef(thisenv, result);
 }
 
@@ -485,18 +485,18 @@ SEXP Rf_installChar(SEXP charsxp) {
 	TRACE(TARGp, charsxp);
 	JNIEnv *thisenv = getEnv();
 	jstring string = stringFromCharSXP(thisenv, charsxp);
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_installMethodID, string);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_installMethodID, string);
 	return checkRef(thisenv, result);
 }
 
 Rboolean Rf_isNull(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_isNullMethodID, s);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_isNullMethodID, s);
 }
 
 Rboolean Rf_isString(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_isStringMethodID, s);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_isStringMethodID, s);
 }
 
 Rboolean R_cycle_detected(SEXP s, SEXP child) {
@@ -527,7 +527,7 @@ SEXP Rf_mkCharLenCE(const char *x, int len, cetype_t enc) {
 	JNIEnv *thisenv = getEnv();
 	jbyteArray bytes = (*thisenv)->NewByteArray(thisenv, len);
 	(*thisenv)->SetByteArrayRegion(thisenv, bytes, 0, len, (const jbyte *) x);
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_mkCharLenCEMethodID, bytes, (int) enc);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_mkCharLenCEMethodID, bytes, (int) enc);
 	return checkRef(thisenv, result);
 }
 
@@ -543,13 +543,13 @@ SEXP Rf_mkString(const char *s) {
 int Rf_ncols(SEXP x) {
 	TRACE(TARGs, x);
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_ncolsMethodID, x);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_ncolsMethodID, x);
 }
 
 int Rf_nrows(SEXP x) {
 	TRACE(TARGs, x);
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_nrowsMethodID, x);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_nrowsMethodID, x);
 }
 
 
@@ -591,7 +591,7 @@ void Rf_error(const char *format, ...) {
 	// RError.error does quite a lot of stuff including potentially searching for R condition handlers
 	// and, if it finds any, does not return, but throws a different exception than RError.
 	// We definitely need to exit the FFI call and we certainly cannot return to our caller.
-	// So we call CallRFFIHelper.Rf_error to throw the RError exception. When the pending
+	// So we call RFFIUpCallsObject.Rf_error to throw the RError exception. When the pending
 	// exception (whatever it is) is observed by JNI, the call to Rf_error will return where we do a
 	// non-local transfer of control back to the entry point (which will cleanup).
 	char buf[8192];
@@ -602,7 +602,7 @@ void Rf_error(const char *format, ...) {
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, buf);
 	// This will set a pending exception
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_errorMethodID, string);
+	(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_errorMethodID, string);
 	// just transfer back which will cleanup and exit the entire JNI call
 	longjmp(*getErrorJmpBuf(), 1);
 
@@ -620,7 +620,7 @@ void Rf_warningcall(SEXP x, const char *format, ...) {
 	va_end(ap);
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, buf);
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_warningcallMethodID, x, string);
+	(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_warningcallMethodID, x, string);
 }
 
 void Rf_warning(const char *format, ...) {
@@ -631,7 +631,7 @@ void Rf_warning(const char *format, ...) {
 	va_end(ap);
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, buf);
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_warningMethodID, string);
+	(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_warningMethodID, string);
 }
 
 void Rprintf(const char *format, ...) {
@@ -642,7 +642,7 @@ void Rprintf(const char *format, ...) {
 	va_end(ap);
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, buf);
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, RprintfMethodID, string);
+	(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, RprintfMethodID, string);
 }
 
 /*
@@ -660,7 +660,7 @@ void REprintf(const char *format, ...)
 	va_end(ap);
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, buf);
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, RprintfMethodID, string);
+	(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, RprintfMethodID, string);
 }
 
 void Rvprintf(const char *format, va_list args) {
@@ -681,13 +681,13 @@ void R_ProcessEvents(void) {
 // Tools package support, not in public API
 SEXP R_NewHashedEnv(SEXP parent, SEXP size) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_NewHashedEnvMethodID, parent, size);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_NewHashedEnvMethodID, parent, size);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_classgets(SEXP vec, SEXP klass) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_classgetsMethodID, vec, klass);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_classgetsMethodID, vec, klass);
 	return checkRef(thisenv, result);
 }
 
@@ -716,7 +716,7 @@ SEXP Rf_lengthgets(SEXP x, R_len_t y) {
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
 	invalidateNativeArray(thisenv, x);
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_lengthgetsMethodID, x, y);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_lengthgetsMethodID, x, y);
 	return checkRef(thisenv, result);
 }
 
@@ -731,7 +731,7 @@ SEXP R_lsInternal(SEXP env, Rboolean all) {
 
 SEXP R_lsInternal3(SEXP env, Rboolean all, Rboolean sorted) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_lsInternal3MethodID, env, all, sorted);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_lsInternal3MethodID, env, all, sorted);
 	return checkRef(thisenv, result);
 }
 
@@ -742,7 +742,7 @@ SEXP Rf_namesgets(SEXP x, SEXP y) {
 SEXP GetOption1(SEXP tag)
 {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_GetOption1MethodID, tag);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_GetOption1MethodID, tag);
 	return checkRef(thisenv, result);
 }
 
@@ -803,34 +803,34 @@ Rboolean Rf_GetOptionDeviceAsk(void)
 void Rf_gsetVar(SEXP symbol, SEXP value, SEXP rho)
 {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_gsetVarMethodID, symbol, value, rho);
+	(*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_gsetVarMethodID, symbol, value, rho);
 }
 
 SEXP TAG(SEXP e) {
     TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, TAG_MethodID, e);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, TAG_MethodID, e);
     return checkRef(thisenv, result);
 }
 
 SEXP PRINTNAME(SEXP e) {
     TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, PRINTNAME_MethodID, e);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, PRINTNAME_MethodID, e);
     return checkRef(thisenv, result);
 }
 
 SEXP CAR(SEXP e) {
     TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CAR_MethodID, e);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, CAR_MethodID, e);
     return checkRef(thisenv, result);
 }
 
 SEXP CDR(SEXP e) {
     TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CDR_MethodID, e);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, CDR_MethodID, e);
     return checkRef(thisenv, result);
 }
 
@@ -847,14 +847,14 @@ SEXP CDAR(SEXP e) {
 SEXP CADR(SEXP e) {
     TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CADR_MethodID, e);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, CADR_MethodID, e);
     return checkRef(thisenv, result);
 }
 
 SEXP CDDR(SEXP e) {
     TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CDDR_MethodID, e);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, CDDR_MethodID, e);
     return checkRef(thisenv, result);
 }
 
@@ -866,7 +866,7 @@ SEXP CDDDR(SEXP e) {
 SEXP CADDR(SEXP e) {
     TRACE(TARGp, e);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CADDR_MethodID, e);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, CADDR_MethodID, e);
     return checkRef(thisenv, result);
 }
 
@@ -892,27 +892,27 @@ void SET_MISSING(SEXP x, int v) {
 void SET_TAG(SEXP x, SEXP y) {
     TRACE(TARGpp, x, y);
     JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SET_TAG_MethodID, x, y);
+    (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, SET_TAG_MethodID, x, y);
 }
 
 SEXP SETCAR(SEXP x, SEXP y) {
     TRACE(TARGpp, x, y);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SETCAR_MethodID, x, y);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, SETCAR_MethodID, x, y);
     return checkRef(thisenv, result);
 }
 
 SEXP SETCDR(SEXP x, SEXP y) {
     TRACE(TARGpp, x, y);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SETCDR_MethodID, x, y);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, SETCDR_MethodID, x, y);
     return checkRef(thisenv, result);
 }
 
 SEXP SETCADR(SEXP x, SEXP y) {
     TRACE(TARGpp, x, y);
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SETCADR_MethodID, x, y);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, SETCADR_MethodID, x, y);
     return checkRef(thisenv, result);
 }
 
@@ -945,12 +945,12 @@ SEXP CLOENV(SEXP x) {
 
 int RDEBUG(SEXP x) {
     JNIEnv *thisenv = getEnv();
-    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, RDEBUGMethodID, x);
+    return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, RDEBUGMethodID, x);
 }
 
 int RSTEP(SEXP x) {
     JNIEnv *thisenv = getEnv();
-    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, RSTEPMethodID, x);
+    return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, RSTEPMethodID, x);
 }
 
 int RTRACE(SEXP x) {
@@ -960,12 +960,12 @@ int RTRACE(SEXP x) {
 
 void SET_RDEBUG(SEXP x, int v) {
     JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_RDEBUGMethodID, x, v);
+    (*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, SET_RDEBUGMethodID, x, v);
 }
 
 void SET_RSTEP(SEXP x, int v) {
     JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_RSTEPMethodID, x, v);
+    (*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, SET_RSTEPMethodID, x, v);
 }
 
 void SET_RTRACE(SEXP x, int v) {
@@ -986,7 +986,7 @@ void SET_CLOENV(SEXP x, SEXP v) {
 
 SEXP SYMVALUE(SEXP x) {
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SYMVALUE_MethodID, x);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, SYMVALUE_MethodID, x);
     return checkRef(thisenv, result);
 }
 
@@ -1005,7 +1005,7 @@ void SET_DDVAL(SEXP x, int v) {
 
 void SET_SYMVALUE(SEXP x, SEXP v) {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_SYMVALUE_MethodID, x, v);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, SET_SYMVALUE_MethodID, x, v);
 }
 
 void SET_INTERNAL(SEXP x, SEXP v) {
@@ -1018,7 +1018,7 @@ SEXP FRAME(SEXP x) {
 
 SEXP ENCLOS(SEXP x) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, ENCLOSMethodID, x);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, ENCLOSMethodID, x);
     return checkRef(thisenv, result);
 }
 
@@ -1059,7 +1059,7 @@ SEXP PRENV(SEXP x) {
 
 SEXP PRVALUE(SEXP x) {
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, PRVALUEMethodID, x);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, PRVALUEMethodID, x);
     return checkRef(thisenv, result);
 }
 
@@ -1086,7 +1086,7 @@ void SET_PRCODE(SEXP x, SEXP v) {
 int LENGTH(SEXP x) {
     TRACE(TARGp, x);
     JNIEnv *thisenv = getEnv();
-    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, LENGTH_MethodID, x);
+    return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, LENGTH_MethodID, x);
 }
 
 int TRUELENGTH(SEXP x){
@@ -1172,7 +1172,7 @@ Rcomplex *COMPLEX(SEXP x){
 SEXP STRING_ELT(SEXP x, R_xlen_t i){
 	TRACE(TARGpd, x, i);
 	JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, STRING_ELT_MethodID, x, i);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, STRING_ELT_MethodID, x, i);
     return checkRef(thisenv, result);
 }
 
@@ -1180,21 +1180,21 @@ SEXP STRING_ELT(SEXP x, R_xlen_t i){
 SEXP VECTOR_ELT(SEXP x, R_xlen_t i){
 	TRACE(TARGpd, x, i);
 	JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, VECTOR_ELT_MethodID, x, i);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, VECTOR_ELT_MethodID, x, i);
     return checkRef(thisenv, result);
 }
 
 void SET_STRING_ELT(SEXP x, R_xlen_t i, SEXP v){
 	TRACE("%s(%p, %d, %p)\n", x, i, v);
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_STRING_ELT_MethodID, x, i, v);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, SET_STRING_ELT_MethodID, x, i, v);
 }
 
 
 SEXP SET_VECTOR_ELT(SEXP x, R_xlen_t i, SEXP v){
 	TRACE("%s(%p, %d, %p)\n", x, i, v);
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, SET_VECTOR_ELT_MethodID, x, i, v);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, SET_VECTOR_ELT_MethodID, x, i, v);
 	return v;
 }
 
@@ -1213,14 +1213,14 @@ SEXP *VECTOR_PTR(SEXP x){
 SEXP Rf_asChar(SEXP x){
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_asCharMethodID, x);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_asCharMethodID, x);
 	return checkRef(thisenv, result);
 }
 
 SEXP Rf_PairToVectorList(SEXP x){
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_PairToVectorListMethodID, x);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_PairToVectorListMethodID, x);
 	return checkRef(thisenv, result);
 }
 
@@ -1237,19 +1237,19 @@ SEXP Rf_asCharacterFactor(SEXP x){
 int Rf_asLogical(SEXP x){
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_asLogicalMethodID, x);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_asLogicalMethodID, x);
 }
 
 int Rf_asInteger(SEXP x) {
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_asIntegerMethodID, x);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_asIntegerMethodID, x);
 }
 
 //double Rf_asReal(SEXP x) {
 //	TRACE(TARGp, x);
 //	JNIEnv *thisenv = getEnv();
-//	return (*thisenv)->CallStaticDoubleMethod(thisenv, CallRFFIHelperClass, Rf_asRealMethodID, x);
+//	return (*thisenv)->CallDoubleMethod(thisenv, UpCallsRFFIObject, Rf_asRealMethodID, x);
 //}
 
 Rcomplex Rf_asComplex(SEXP x){
@@ -1260,7 +1260,7 @@ Rcomplex Rf_asComplex(SEXP x){
 int TYPEOF(SEXP x) {
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, TYPEOF_MethodID, x);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, TYPEOF_MethodID, x);
 }
 
 SEXP ATTRIB(SEXP x){
@@ -1270,7 +1270,7 @@ SEXP ATTRIB(SEXP x){
 
 int OBJECT(SEXP x){
 	JNIEnv *env = getEnv();
-	return 	(*env)->CallStaticIntMethod(env, CallRFFIHelperClass, OBJECT_MethodID, x);
+	return 	(*env)->CallIntMethod(env, UpCallsRFFIObject, OBJECT_MethodID, x);
 }
 
 int MARK(SEXP x){
@@ -1280,7 +1280,7 @@ int MARK(SEXP x){
 
 int NAMED(SEXP x){
     JNIEnv *thisenv = getEnv();
-    return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, NAMED_MethodID, x);
+    return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, NAMED_MethodID, x);
 }
 
 int REFCNT(SEXP x){
@@ -1298,7 +1298,7 @@ void SET_TYPEOF(SEXP x, int v){
 
 SEXP SET_TYPEOF_FASTR(SEXP x, int v){
     JNIEnv *thisenv = getEnv();
-    SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, SET_TYPEOF_FASTR_MethodID, x, v);
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, SET_TYPEOF_FASTR_MethodID, x, v);
     return checkRef(thisenv, result);
 }
 
@@ -1312,7 +1312,7 @@ void SET_ATTRIB(SEXP x, SEXP v){
 
 void DUPLICATE_ATTRIB(SEXP to, SEXP from){
     JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, DUPLICATE_ATTRIB_MethodID, to, from);
+    (*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, DUPLICATE_ATTRIB_MethodID, to, from);
 }
 
 char *dgettext(const char *domainname, const char *msgid) {
@@ -1367,7 +1367,7 @@ R_len_t R_BadLongVector(SEXP x, const char *y, int z) {
 
 int IS_S4_OBJECT(SEXP x) {
 	JNIEnv *env = getEnv();
-	return 	(*env)->CallStaticIntMethod(env, CallRFFIHelperClass, isS4ObjectMethodID, x);
+	return 	(*env)->CallIntMethod(env, UpCallsRFFIObject, isS4ObjectMethodID, x);
 }
 
 void SET_S4_OBJECT(SEXP x) {
@@ -1379,9 +1379,9 @@ void UNSET_S4_OBJECT(SEXP x) {
 
 Rboolean R_ToplevelExec(void (*fun)(void *), void *data) {
 	JNIEnv *env = getEnv();
-	jobject handlerStacks = (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, resetAndGetHandlerStacksMethodID);
+	jobject handlerStacks = (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_ToplevelExecMethodID);
 	fun(data);
-	(*env)->CallStaticVoidMethod(env, CallRFFIHelperClass, restoreHandlerStacksMethodID, handlerStacks);
+	(*env)->CallVoidMethod(env, UpCallsRFFIObject, restoreHandlerStacksMethodID, handlerStacks);
 	// TODO how do we detect error
 	return TRUE;
 }
@@ -1418,7 +1418,7 @@ SEXP R_NamespaceEnvSpec(SEXP rho) {
 
 SEXP R_FindNamespace(SEXP info) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_FindNamespaceMethodID, info);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_FindNamespaceMethodID, info);
 	return checkRef(thisenv, result);
 }
 
@@ -1444,7 +1444,7 @@ void R_MakeActiveBinding(SEXP sym, SEXP fun, SEXP env) {
 
 Rboolean R_BindingIsLocked(SEXP sym, SEXP env) {
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, R_BindingIsLockedID, sym, env);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, R_BindingIsLockedID, sym, env);
 }
 
 Rboolean R_BindingIsActive(SEXP sym, SEXP env) {
@@ -1467,7 +1467,7 @@ SEXP Rf_asS4(SEXP x, Rboolean b, int i) {
 static SEXP R_tryEvalInternal(SEXP x, SEXP y, int *ErrorOccurred, jboolean silent) {
 	JNIEnv *thisenv = getEnv();
     updateNativeArrays(thisenv);
-	jobject tryResult =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_tryEvalMethodID, x, y, silent);
+	jobject tryResult =  (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_tryEvalMethodID, x, y, silent);
 	// If tryResult is NULL, an error occurred
 	if (ErrorOccurred) {
 		*ErrorOccurred = tryResult == NULL;
@@ -1507,40 +1507,40 @@ SEXP R_forceAndCall(SEXP e, int n, SEXP rho) {
 
 SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_MakeExternalPtrMethodID, (jlong) p, tag, prot);
+	SEXP result =  (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_MakeExternalPtrMethodID, (jlong) p, tag, prot);
     return checkRef(thisenv, result);
 }
 
 void *R_ExternalPtrAddr(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	return (void *) (*thisenv)->CallStaticLongMethod(thisenv, CallRFFIHelperClass, R_ExternalPtrAddrMethodID, s);
+	return (void *) (*thisenv)->CallLongMethod(thisenv, UpCallsRFFIObject, R_ExternalPtrAddrMethodID, s);
 }
 
 SEXP R_ExternalPtrTag(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_ExternalPtrTagMethodID, s);
+	SEXP result =  (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_ExternalPtrTagMethodID, s);
     return checkRef(thisenv, result);
 }
 
 SEXP R_ExternalPtrProt(SEXP s) {
 	JNIEnv *thisenv = getEnv();
-	SEXP result =  (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_ExternalPtrProtMethodID, s);
+	SEXP result =  (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_ExternalPtrProtMethodID, s);
     return checkRef(thisenv, result);
 }
 
 void R_SetExternalPtrAddr(SEXP s, void *p) {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, R_SetExternalPtrAddrMethodID, s, (jlong) p);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, R_SetExternalPtrAddrMethodID, s, (jlong) p);
 }
 
 void R_SetExternalPtrTag(SEXP s, SEXP tag) {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, R_SetExternalPtrTagMethodID, s, tag);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, R_SetExternalPtrTagMethodID, s, tag);
 }
 
 void R_SetExternalPtrProtected(SEXP s, SEXP p) {
 	JNIEnv *thisenv = getEnv();
-	(*thisenv)->CallStaticVoidMethod(thisenv, CallRFFIHelperClass, R_SetExternalPtrProtMethodID, s, p);
+	(*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, R_SetExternalPtrProtMethodID, s, p);
 }
 
 void R_ClearExternalPtr(SEXP s) {
@@ -1602,7 +1602,7 @@ int R_has_slot(SEXP obj, SEXP name) {
 SEXP R_do_MAKE_CLASS(const char *what) {
 	JNIEnv *thisenv = getEnv();
 	jstring string = (*thisenv)->NewStringUTF(thisenv, what);
-	return (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_do_MAKE_CLASS_MethodID, string);
+	return (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_do_MAKE_CLASS_MethodID, string);
 }
 
 SEXP R_getClassDef (const char *what) {
@@ -1637,15 +1637,15 @@ void R_dot_Last(void) {
 
 Rboolean R_compute_identical(SEXP x, SEXP y, int flags) {
 	JNIEnv *thisenv = getEnv();
-	return (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, R_computeIdenticalMethodID, x, y, flags);
+	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, R_computeIdenticalMethodID, x, y, flags);
 }
 
 void Rf_copyListMatrix(SEXP s, SEXP t, Rboolean byrow) {
 	JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_copyListMatrixMethodID, s, t, byrow);
+    (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_copyListMatrixMethodID, s, t, byrow);
 }
 
 void Rf_copyMatrix(SEXP s, SEXP t, Rboolean byrow) {
 	JNIEnv *thisenv = getEnv();
-    (*thisenv)->CallStaticIntMethod(thisenv, CallRFFIHelperClass, Rf_copyMatrixMethodID, s, t, byrow);
+    (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_copyMatrixMethodID, s, t, byrow);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/call_rffi.c b/com.oracle.truffle.r.native/fficall/src/jni/call_rffi.c
index 7b9a14296c810e03a53a5ac1c6b10329b1006599..eb81606672d73f8a5cfee40801ca109e6ce7e0c0 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/call_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/call_rffi.c
@@ -25,10 +25,11 @@
 #include <string.h>
 #include <setjmp.h>
 
+// The entry point from JNI_Call that initializes the system
 JNIEXPORT void JNICALL
 Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Call_initialize(JNIEnv *env, jclass c,
-		jobjectArray initialValues) {
-	init_utils(env); // must be first
+		jobject upCallInstance, jobjectArray initialValues) {
+	init_utils(env, upCallInstance); // must be first
 	init_variables(env, initialValues);
 	init_dynload(env);
 	init_internals(env);
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
index 0010587bccde3b3ea603407a66e2a05727d9f2f9..69d19f2aec5742fcbc96b2bd11340a324ccf3bcf 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
@@ -32,11 +32,10 @@
  * so we are safe to use static variables. TODO Figure out where to store such state
  * (portably) for MT use. JNI provides no help.
  */
-jclass CallRFFIHelperClass;
+jclass UpCallsRFFIClass;
+jobject UpCallsRFFIObject;
 jclass CharSXPWrapperClass;
 
-static jmethodID validateMethodID;
-
 static JNIEnv *curenv = NULL;
 
 // default for trace output when enabled
@@ -87,8 +86,10 @@ static int nativeArrayTableHwmStack[CALLDEPTH_STACK_SIZE];
 static jmp_buf* callErrorJmpBufTable[CALLDEPTH_STACK_SIZE];
 
 
-void init_utils(JNIEnv *env) {
+void init_utils(JNIEnv *env, jobject upCallsInstance) {
 	curenv = env;
+	UpCallsRFFIClass = (*env)->GetObjectClass(env, upCallsInstance);
+	UpCallsRFFIObject = (*env)->NewGlobalRef(env, upCallsInstance);
 	if (TRACE_ENABLED && traceFile == NULL) {
 		if (!isEmbedded) {
 			traceFile = stdout;
@@ -109,8 +110,6 @@ void init_utils(JNIEnv *env) {
 		    setvbuf(traceFile, (char*) NULL, _IONBF, 0);
 		}
 	}
-	CallRFFIHelperClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper");
-    validateMethodID = checkGetMethodID(env, CallRFFIHelperClass, "validate", "(Ljava/lang/Object;)Ljava/lang/Object;", 1);
     cachedGlobalRefs = calloc(CACHED_GLOBALREFS_INITIAL_SIZE, sizeof(GlobalRefElem));
     cachedGlobalRefsLength = CACHED_GLOBALREFS_INITIAL_SIZE;
     cachedGlobalRefsHwm = 0;
@@ -230,7 +229,7 @@ void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) {
 		jarray jArray;
 		switch (type) {
 		case INTSXP: {
-			jintArray intArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, INTEGER_MethodID, x);
+			jintArray intArray = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, INTEGER_MethodID, x);
 			int len = (*thisenv)->GetArrayLength(thisenv, intArray);
 			data = (*thisenv)->GetIntArrayElements(thisenv, intArray, &isCopy);
 			jArray = intArray;
@@ -238,7 +237,7 @@ void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) {
 		}
 
 		case REALSXP: {
-			jdoubleArray doubleArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, REAL_MethodID, x);
+			jdoubleArray doubleArray = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, REAL_MethodID, x);
 			int len = (*thisenv)->GetArrayLength(thisenv, doubleArray);
 			data = (*thisenv)->GetDoubleArrayElements(thisenv, doubleArray, &isCopy);
 			jArray = doubleArray;
@@ -246,7 +245,7 @@ void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) {
 		}
 
 		case RAWSXP: {
-		    jbyteArray byteArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, RAW_MethodID, x);
+		    jbyteArray byteArray = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, RAW_MethodID, x);
 		    int len = (*thisenv)->GetArrayLength(thisenv, byteArray);
 		    data = (*thisenv)->GetByteArrayElements(thisenv, byteArray, &isCopy);
 	        jArray = byteArray;
@@ -255,7 +254,7 @@ void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) {
 
 		case LGLSXP: {
 			// Special treatment becuase R FFI wants int* and FastR represents using byte[]
-		    jbyteArray byteArray = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, LOGICAL_MethodID, x);
+		    jbyteArray byteArray = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, LOGICAL_MethodID, x);
 		    int len = (*thisenv)->GetArrayLength(thisenv, byteArray);
 		    jbyte* internalData = (*thisenv)->GetByteArrayElements(thisenv, byteArray, &isCopy);
 		    int* idata = malloc(len * sizeof(int));
@@ -333,7 +332,7 @@ static void releaseNativeArray(JNIEnv *env, int i, int freedata) {
 			fatalError("releaseNativeArray type");
 		}
 		// update complete status
-		(*env)->CallVoidMethod(env, cv.obj, setCompleteMethodID, cv.obj, complete);
+		(*env)->CallVoidMethod(env, UpCallsRFFIObject, setCompleteMethodID, cv.obj, complete);
 
         if (freedata) {
             // free up the slot
@@ -427,10 +426,6 @@ void validateRef(JNIEnv *env, SEXP x, const char *msg) {
 	}
 }
 
-void validate(SEXP x) {
-	(*curenv)->CallStaticObjectMethod(curenv, CallRFFIHelperClass, validateMethodID, x);
-}
-
 JNIEnv *getEnv() {
 //	fprintf(traceFile, "getEnv()=%p\n", curenv);
 	return curenv;
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
index 3a3539579ec0912b64229bbe5709c4c1cab4c719..99732f93766987fdceb40035a84eacce6111d882 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
@@ -76,12 +76,12 @@ void updateNativeArrays(JNIEnv *env);
 
 SEXP addGlobalRef(JNIEnv *env, SEXP obj, int permanent);
 
+void init_utils(JNIEnv *env, jobject upCallsInstance);
 void init_rmath(JNIEnv *env);
 void init_variables(JNIEnv *env, jobjectArray initialValues);
 void init_dynload(JNIEnv *env);
 void init_internals(JNIEnv *env);
 void init_random(JNIEnv *env);
-void init_utils(JNIEnv *env);
 void init_parse(JNIEnv *env);
 void init_pcre(JNIEnv *env);
 void init_c(JNIEnv *env);
@@ -90,7 +90,8 @@ void setEmbedded(void);
 
 void setTempDir(JNIEnv *, jstring tempDir);
 
-extern jclass CallRFFIHelperClass;
+extern jclass UpCallsRFFIClass;
+extern jobject UpCallsRFFIObject;
 extern FILE *traceFile;
 
 // tracing/debugging support, set to 1 and recompile to enable
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/userrng_rffi.c b/com.oracle.truffle.r.native/fficall/src/jni/userrng_rffi.c
index a946f23f8b1f9fbcc72322e199a1103afe3649a8..fd510c9e56eaa4985c9067a574bf6a2b092415ed 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/userrng_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/userrng_rffi.c
@@ -29,27 +29,27 @@ typedef int* (*call_nSeed)(void);
 typedef int* (*call_seeds)(void);
 
 JNIEXPORT void JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_init(JNIEnv *env, jclass c, jlong address, jint seed) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_nativeInit(JNIEnv *env, jclass c, jlong address, jint seed) {
 	call_init f = (call_init) address;
 	f(seed);
 }
 
 JNIEXPORT double JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_rand(JNIEnv *env, jclass c, jlong address) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_nativeRand(JNIEnv *env, jclass c, jlong address) {
 	call_rand f = (call_rand) address;
 	double* dp = f();
 	return *dp;
 }
 
 JNIEXPORT jint JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_nSeed(JNIEnv *env, jclass c, jlong address) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_nativeNSeed(JNIEnv *env, jclass c, jlong address) {
 	call_nSeed f = (call_nSeed) address;
 	int *pn = f();
 	return *pn;
 }
 
 JNIEXPORT void JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_seeds(JNIEnv *env, jclass c, jlong address, jintArray seedsArray) {
+Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1UserRng_nativeSeeds(JNIEnv *env, jclass c, jlong address, jintArray seedsArray) {
 	call_seeds f = (call_seeds) address;
 	int *pseeds = f();
 	int seedslen = (*env)->GetArrayLength(env, seedsArray);
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/variables.c b/com.oracle.truffle.r.native/fficall/src/jni/variables.c
index ca381df5e2e84d8b6568bca259034d09d8227244..aaf00d68fee482eaa1fbae06c1421eb1593b189e 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/variables.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/variables.c
@@ -31,37 +31,37 @@
 #include <rffiutils.h>
 #include <variable_defs.h>
 
-jmethodID getGlobalEnvMethodID;
-jmethodID getBaseEnvMethodID;
-jmethodID getBaseNamespaceMethodID;
-jmethodID getNamespaceRegistryMethodID;
+jmethodID R_GlobalEnvMethodID;
+jmethodID R_BaseEnvMethodID;
+jmethodID R_BaseNamespaceMethodID;
+jmethodID R_NamespaceRegistryMethodID;
 jmethodID isInteractiveMethodID;
-jmethodID getGlobalContextMethodID;
+jmethodID R_GlobalContextMethodID;
 
 // R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
 SEXP FASTR_GlobalEnv() {
 	JNIEnv *env = getEnv();
-	return (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getGlobalEnvMethodID);
+	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_GlobalEnvMethodID);
 }
 
 SEXP FASTR_BaseEnv() {
 	JNIEnv *env = getEnv();
-	return (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getBaseEnvMethodID);
+	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_BaseEnvMethodID);
 }
 
 SEXP FASTR_BaseNamespace() {
 	JNIEnv *env = getEnv();
-	return (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getBaseNamespaceMethodID);
+	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_BaseNamespaceMethodID);
 }
 
 SEXP FASTR_NamespaceRegistry() {
 	JNIEnv *env = getEnv();
-	return (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getNamespaceRegistryMethodID);
+	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_NamespaceRegistryMethodID);
 }
 
 CTXT FASTR_GlobalContext() {
 	JNIEnv *env = getEnv();
-	CTXT res = (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getGlobalContextMethodID);
+	CTXT res = (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_GlobalContextMethodID);
     return addGlobalRef(env, res, 0);
 }
 
@@ -77,12 +77,12 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) {
 	jmethodID doubleValueMethodID = checkGetMethodID(env, doubleClass, "doubleValue", "()D", 0);
 	jmethodID intValueMethodID = checkGetMethodID(env, intClass, "intValue", "()I", 0);
 
-	getGlobalEnvMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getGlobalEnv", "()Ljava/lang/Object;", 1);
-	getBaseEnvMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getBaseEnv", "()Ljava/lang/Object;", 1);
-	getBaseNamespaceMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getBaseNamespace", "()Ljava/lang/Object;", 1);
-	getNamespaceRegistryMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getNamespaceRegistry", "()Ljava/lang/Object;", 1);
-	isInteractiveMethodID = checkGetMethodID(env, CallRFFIHelperClass, "isInteractive", "()I", 1);
-	getGlobalContextMethodID = checkGetMethodID(env, CallRFFIHelperClass, "getGlobalContext", "()Ljava/lang/Object;", 1);
+	R_GlobalEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_GlobalEnv", "()Ljava/lang/Object;", 0);
+	R_BaseEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_BaseEnv", "()Ljava/lang/Object;", 0);
+	R_BaseNamespaceMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_BaseNamespace", "()Ljava/lang/Object;", 0);
+	R_NamespaceRegistryMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_NamespaceRegistry", "()Ljava/lang/Object;", 0);
+	isInteractiveMethodID = checkGetMethodID(env, UpCallsRFFIClass, "isInteractive", "()I", 0);
+	R_GlobalContextMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_GlobalContext", "()Ljava/lang/Object;", 0);
 
 	int length = (*env)->GetArrayLength(env, initialValues);
 	int index;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
index 0550a55c3bdd9628b69680a20f5fda5193ade6b6..535045ab1cba59cf3f21c3d8f60549161d9a1f2c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
@@ -38,6 +38,7 @@ import com.oracle.truffle.r.nodes.builtin.base.BaseVariables;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -50,8 +51,6 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.DLL.DLLException;
 
 /**
  * Support for loading the base package and also optional overrides for the packages provided with
@@ -98,11 +97,10 @@ public final class RBuiltinPackages implements RBuiltinLookup {
             Utils.rSuicide(String.format("unable to open the base package %s", basePathbase));
         }
         // Load the (stub) DLL for base
-        try {
-            DLL.loadPackageDLL(baseDirPath.resolve("libs").resolve("base.so").toString(), true, true);
-        } catch (DLLException ex) {
-            Utils.rSuicide(ex.getMessage());
-        }
+        String path = baseDirPath.resolve("libs").resolve("base.so").toString();
+        Source loadSource = RSource.fromTextInternal(".Internal(dyn.load(" + RRuntime.quoteString(path, false) + ", TRUE, TRUE, \"\"))", RSource.Internal.R_IMPL);
+        RContext.getEngine().parseAndEval(loadSource, baseFrame, false);
+
         // Any RBuiltinKind.SUBSTITUTE functions installed above should not be overridden
         try {
             RContext.getInstance().setLoadingBase(true);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
index 472fdc3f53b299f573acac83050b028769cddef2..14a7bd1687650116a8d7b22ee82b2c5f6fa1de90 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
@@ -23,13 +23,15 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -61,10 +63,12 @@ public abstract class APerm extends RBuiltinNode {
     }
 
     @Specialization
-    protected RAbstractVector aPerm(RAbstractVector vector, @SuppressWarnings("unused") RNull permVector, byte resize) {
+    protected RAbstractVector aPerm(RAbstractVector vector, @SuppressWarnings("unused") RNull permVector, byte resize,
+                    @Cached("create()") GetDimAttributeNode getDimsNode,
+                    @Cached("create()") SetDimAttributeNode setDimNode) {
         checkErrorConditions(vector);
 
-        int[] dim = vector.getDimensions();
+        int[] dim = getDimsNode.getDimensions(vector);
         final int diml = dim.length;
 
         RVector<?> result = vector.createEmptySameType(vector.getLength(), vector.isComplete());
@@ -74,9 +78,9 @@ public abstract class APerm extends RBuiltinNode {
             for (int i = 0; i < diml; i++) {
                 pDim[i] = dim[diml - 1 - i];
             }
-            result.setDimensions(pDim);
+            setDimNode.setDimensions(result, pDim);
         } else {
-            result.setDimensions(dim);
+            setDimNode.setDimensions(result, dim);
         }
 
         // Move along the old array using stride
@@ -101,10 +105,12 @@ public abstract class APerm extends RBuiltinNode {
     }
 
     @Specialization
-    protected RAbstractVector aPerm(RAbstractVector vector, RAbstractIntVector permVector, byte resize) {
+    protected RAbstractVector aPerm(RAbstractVector vector, RAbstractIntVector permVector, byte resize,
+                    @Cached("create()") GetDimAttributeNode getDimsNode,
+                    @Cached("create()") SetDimAttributeNode setDimsNode) {
         checkErrorConditions(vector);
 
-        int[] dim = vector.getDimensions();
+        int[] dim = getDimsNode.getDimensions(vector);
         int[] perm = getPermute(dim, permVector);
 
         int[] posV = new int[dim.length];
@@ -112,7 +118,7 @@ public abstract class APerm extends RBuiltinNode {
 
         RVector<?> result = vector.createEmptySameType(vector.getLength(), vector.isComplete());
 
-        result.setDimensions(resize == RRuntime.LOGICAL_TRUE ? pDim : dim);
+        setDimsNode.setDimensions(result, resize == RRuntime.LOGICAL_TRUE ? pDim : dim);
 
         // Move along the old array using stride
         for (int i = 0; i < result.getLength(); i++) {
@@ -126,8 +132,10 @@ public abstract class APerm extends RBuiltinNode {
 
     @Specialization
     protected RAbstractVector aPerm(RAbstractVector vector, RAbstractStringVector permVector, byte resize,
-                    @Cached("create()") RAttributeProfiles dimNamesProfile) {
-        RList dimNames = vector.getDimNames(dimNamesProfile);
+                    @Cached("create()") GetDimAttributeNode getDimsNode,
+                    @Cached("create()") SetDimAttributeNode setDimsNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (dimNames == null) {
             // TODO: this error is reported after IS_OF_WRONG_LENGTH in GnuR
             errorProfile.enter();
@@ -146,7 +154,7 @@ public abstract class APerm extends RBuiltinNode {
         }
 
         // Note: if this turns out to be slow, we can cache the permutation
-        return aPerm(vector, RDataFactory.createIntVector(perm, true), resize);
+        return aPerm(vector, RDataFactory.createIntVector(perm, true), resize, getDimsNode, setDimsNode);
     }
 
     private static int[] getReverse(int[] dim) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java
index 7f4e8cce164aac257f239c20c70fec86743ec20c..66b265248d07db9cba90963185681d91f64c38a3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Abbrev.java
@@ -11,7 +11,8 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -20,7 +21,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -29,7 +29,6 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 @RBuiltin(name = "abbreviate", kind = INTERNAL, parameterNames = {"x", "minlength", "use.classes"}, behavior = PURE)
 public abstract class Abbrev extends RBuiltinNode {
     private final NACheck naCheck = NACheck.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
 
     @Override
     public void createCasts(CastBuilder casts) {
@@ -56,7 +55,7 @@ public abstract class Abbrev extends RBuiltinNode {
             }
         }
         RStringVector result = RDataFactory.createStringVector(data, naCheck.neverSeenNA());
-        result.copyAttributesFrom(attrProfiles, x);
+        result.copyAttributesFrom(x);
         return result;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
index 6a9b1e8f907831b7e9dda078125f62727709a886..57c48da529aacc0ff7572c242cf1506658bf41fb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java
@@ -54,20 +54,6 @@ public abstract class AnyNA extends RBuiltinNode {
 
     private final NACheck naCheck = NACheck.create();
 
-    private final boolean recursionAllowed;
-
-    protected AnyNA(boolean recursionAllowed) {
-        this.recursionAllowed = recursionAllowed;
-    }
-
-    protected AnyNA() {
-        this(true);
-    }
-
-    protected boolean isRecursionAllowed() {
-        return recursionAllowed;
-    }
-
     public abstract byte execute(VirtualFrame frame, Object value, boolean recursive);
 
     @Override
@@ -161,13 +147,13 @@ public abstract class AnyNA extends RBuiltinNode {
         return doScalar(false);
     }
 
-    protected AnyNA createRecursive(boolean recursive) {
-        return AnyNANodeGen.create(recursive);
+    protected AnyNA createRecursive() {
+        return AnyNANodeGen.create();
     }
 
-    @Specialization(guards = "isRecursionAllowed()")
+    @Specialization(guards = "recursive")
     protected byte isNA(VirtualFrame frame, RList list, boolean recursive,
-                    @Cached("createRecursive(recursive)") AnyNA recursiveNode,
+                    @Cached("createRecursive()") AnyNA recursiveNode,
                     @Cached("createClassProfile()") ValueProfile elementProfile,
                     @Cached("create()") RLengthNode length) {
 
@@ -183,7 +169,7 @@ public abstract class AnyNA extends RBuiltinNode {
         return RRuntime.LOGICAL_FALSE;
     }
 
-    @Specialization(guards = "!isRecursionAllowed()")
+    @Specialization(guards = "!recursive")
     @SuppressWarnings("unused")
     protected byte isNA(VirtualFrame frame, RList list, boolean recursive) {
         return RRuntime.LOGICAL_FALSE;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java
index 446875d8fee0449ccf2df866acde5d3cd2edcc2c..cb65b88f22320b3eb45e95941ebca3477833382b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCall.java
@@ -30,13 +30,13 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public abstract class AsCall extends RBuiltinNode {
 
     private final ConditionProfile nullNamesProfile = ConditionProfile.createBinaryProfile();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     @Specialization
     protected RLanguage asCallFunction(RList x) {
@@ -89,12 +89,12 @@ public abstract class AsCall extends RBuiltinNode {
             values[i] = x.getDataAtAsObject(i + 1);
         }
         ArgumentsSignature signature;
-        if (nullNamesProfile.profile(x.getNames(attrProfiles) == null)) {
+        if (nullNamesProfile.profile(getNamesNode.getNames(x) == null)) {
             signature = ArgumentsSignature.empty(values.length);
         } else {
             String[] names = new String[length];
             // extract names, converting "" to null
-            RStringVector ns = x.getNames(attrProfiles);
+            RStringVector ns = getNamesNode.getNames(x);
             for (int i = 0; i < length; i++) {
                 String name = ns.getDataAt(i + 1);
                 if (name != null && !name.isEmpty()) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
index 1db6100ba110523fc7cfe097d94b81480a216580..aa4fa4aae80e4c3c73d4609f7965677c5bfb9d74 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
@@ -25,8 +25,9 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
+
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.InheritsNode;
@@ -47,6 +48,7 @@ public abstract class AsCharacterFactor extends RBuiltinNode {
 
     @Child InheritsNode inheritsNode = InheritsNodeGen.create();
     @Child CastToVectorNode castToVectorNode = CastToVectorNode.create();
+    @Child private GetFixedAttributeNode getLevelsAttrNode = GetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
 
     @Specialization
     protected RStringVector doAsCharacterFactor(Object x) {
@@ -57,7 +59,7 @@ public abstract class AsCharacterFactor extends RBuiltinNode {
         RIntVector xVec = (RIntVector) x;
         int n = xVec.getLength();
         String[] data = new String[n];
-        Object levsAttr = xVec.getAttr(RRuntime.LEVELS_ATTR_KEY);
+        Object levsAttr = getLevelsAttrNode.execute(xVec);
         Object levs;
         if (levsAttr == null || !((levs = castToVectorNode.execute(levsAttr)) instanceof RAbstractStringVector)) {
             throw RError.error(RError.SHOW_CALLER, RError.Message.MALFORMED_FACTOR);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
index c9e2d6aaf5be2238ac970c9e394ab5d1354f4615..10853a996c8aee8f4c672122aeb90f4cee0f4ebd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
@@ -31,14 +31,15 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetRowNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.UpdateSharedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -62,7 +63,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 public abstract class Attr extends RBuiltinNode {
 
     private final ConditionProfile searchPartialProfile = ConditionProfile.createBinaryProfile();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final BranchProfile errorProfile = BranchProfile.create();
 
     @CompilationFinal private String cachedName = "";
@@ -146,13 +146,14 @@ public abstract class Attr extends RBuiltinNode {
     }
 
     @Specialization(guards = "isRowNamesAttr(name)")
-    protected Object attrRowNames(RAbstractContainer container, @SuppressWarnings("unused") String name, @SuppressWarnings("unused") boolean exact) {
+    protected Object attrRowNames(RAbstractContainer container, @SuppressWarnings("unused") String name, @SuppressWarnings("unused") boolean exact,
+                    @Cached("create()") GetRowNamesAttributeNode getRowNamesNode) {
         // TODO: if exact == false, check for partial match (there is an ignored tests for it)
         DynamicObject attributes = container.getAttributes();
         if (attributes == null) {
             return RNull.instance;
         } else {
-            return getFullRowNames(container.getRowNames(attrProfiles));
+            return getFullRowNames(getRowNamesNode.getRowNames(container));
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java
index d5579cf6151b85e0587b23fa51245d3452b81101..41a244f231512aea273734c48b29acbdf8bb28d7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -53,6 +54,7 @@ public abstract class Attributes extends RBuiltinNode {
 
     private final BranchProfile rownamesBranch = BranchProfile.create();
     @Child private ArrayAttributeNode arrayAttrAccess = ArrayAttributeNode.create();
+    @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create();
 
     @Specialization
     protected Object attributesNull(RAbstractContainer container, //
@@ -117,11 +119,11 @@ public abstract class Attributes extends RBuiltinNode {
             }
         }
         RList result = RDataFactory.createList(values);
-        result.setNames(RDataFactory.createStringVector(names, true));
+        setNamesNode.setNames(result, RDataFactory.createStringVector(names, true));
         return result;
     }
 
     private static boolean hasAttributes(RAttributable attributable) {
-        return attributable.getAttributes() != null && attributable.getAttributes().size() > 0;
+        return attributable.getAttributes() != null && !attributable.getAttributes().isEmpty();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java
index effc12dc4a140b4275b8d7822ef084206ac59b97..5b82397a22c02c2e4d0295b89b3b570970691762 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BaseGammaFunctions.java
@@ -12,13 +12,13 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.library.stats.StatsUtil.DBLEPSILON;
-import static com.oracle.truffle.r.library.stats.StatsUtil.DBL_MANT_DIG;
-import static com.oracle.truffle.r.library.stats.StatsUtil.DBL_MAX_EXP;
-import static com.oracle.truffle.r.library.stats.StatsUtil.DBL_MIN_EXP;
-import static com.oracle.truffle.r.library.stats.StatsUtil.M_LOG10_2;
-import static com.oracle.truffle.r.library.stats.StatsUtil.M_PI;
-import static com.oracle.truffle.r.library.stats.StatsUtil.fmax2;
+import static com.oracle.truffle.r.library.stats.MathConstants.DBL_EPSILON;
+import static com.oracle.truffle.r.library.stats.MathConstants.DBL_MANT_DIG;
+import static com.oracle.truffle.r.library.stats.MathConstants.DBL_MAX_EXP;
+import static com.oracle.truffle.r.library.stats.MathConstants.DBL_MIN_EXP;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_LOG10_2;
+import static com.oracle.truffle.r.library.stats.MathConstants.M_PI;
+import static com.oracle.truffle.r.library.stats.RMath.fmax2;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.complexValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.runtime.RDispatch.MATH_GROUP_GENERIC;
@@ -300,7 +300,7 @@ public class BaseGammaFunctions {
             // mVal.nz = 0;
             xln = Math.log(x);
             if (kode == 1 /* && m == 1 */) { /* the R case --- for very large x: */
-                double lrg = 1 / (2. * DBLEPSILON);
+                double lrg = 1 / (2. * DBL_EPSILON);
                 if (n == 0 && x * xln > lrg) {
                     // ans[0] = -xln;
                     ans = -xln;
@@ -316,7 +316,7 @@ public class BaseGammaFunctions {
             nx = Math.min(-DBL_MIN_EXP, DBL_MAX_EXP);
             assert (nx == 1021);
             r1m5 = M_LOG10_2; // Rf_d1mach(5);
-            r1m4 = DBLEPSILON * 0.5; // Rf_d1mach(4) * 0.5;
+            r1m4 = DBL_EPSILON * 0.5; // Rf_d1mach(4) * 0.5;
             wdtol = fmax2(r1m4, 0.5e-18); /* 1.11e-16 */
 
             /* elim = approximate exponential over and underflow limit */
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index ce52a7a9c44a63aee2d0e792ec0f4c0203c7665b..c1ccfdd06e08dda7ca09700f1f77d790a2c239fd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -42,10 +42,10 @@ import com.oracle.truffle.r.nodes.builtin.base.fastpaths.MatrixFastPathNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.fastpaths.SetDiffFastPathNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.fastpaths.VectorFastPathsFactory.DoubleFastPathNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.fastpaths.VectorFastPathsFactory.IntegerFastPathNodeGen;
-import com.oracle.truffle.r.nodes.builtin.base.foreign.DotC;
-import com.oracle.truffle.r.nodes.builtin.base.foreign.DotCNodeGen;
-import com.oracle.truffle.r.nodes.builtin.base.foreign.ForeignFunctions;
-import com.oracle.truffle.r.nodes.builtin.base.foreign.ForeignFunctionsFactory;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.CallAndExternalFunctions;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.CallAndExternalFunctionsFactory;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.FortranAndCFunctions;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.FortranAndCFunctionsFactory;
 import com.oracle.truffle.r.nodes.builtin.base.infix.AccessField;
 import com.oracle.truffle.r.nodes.builtin.base.infix.AccessFieldNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.infix.AssignBuiltin;
@@ -221,6 +221,11 @@ public class BasePackage extends RBuiltinPackage {
         add(BrowserFunctions.BrowserSetDebug.class, BrowserFunctionsFactory.BrowserSetDebugNodeGen::create);
         add(BrowserFunctions.BrowserText.class, BrowserFunctionsFactory.BrowserTextNodeGen::create);
         add(Call.class, CallNodeGen::create);
+        add(CallAndExternalFunctions.DotCall.class, CallAndExternalFunctionsFactory.DotCallNodeGen::create);
+        add(CallAndExternalFunctions.DotCallGraphics.class, CallAndExternalFunctionsFactory.DotCallGraphicsNodeGen::create);
+        add(CallAndExternalFunctions.DotExternal.class, CallAndExternalFunctionsFactory.DotExternalNodeGen::create);
+        add(CallAndExternalFunctions.DotExternal2.class, CallAndExternalFunctionsFactory.DotExternal2NodeGen::create);
+        add(CallAndExternalFunctions.DotExternalGraphics.class, CallAndExternalFunctionsFactory.DotExternalGraphicsNodeGen::create);
         add(Capabilities.class, CapabilitiesNodeGen::create);
         add(Cat.class, CatNodeGen::create);
         add(Ceiling.class, CeilingNodeGen::create);
@@ -391,17 +396,12 @@ public class BasePackage extends RBuiltinPackage {
         add(FileFunctions.ListDirs.class, FileFunctionsFactory.ListDirsNodeGen::create);
         add(FileFunctions.Unlink.class, FileFunctionsFactory.UnlinkNodeGen::create);
         add(Floor.class, FloorNodeGen::create);
-        add(DotC.class, DotCNodeGen::create);
         add(ForceAndCall.class, ForceAndCallNodeGen::create);
-        add(ForeignFunctions.DotCall.class, ForeignFunctionsFactory.DotCallNodeGen::create);
-        add(ForeignFunctions.DotCallGraphics.class, ForeignFunctionsFactory.DotCallGraphicsNodeGen::create);
-        add(ForeignFunctions.DotExternal.class, ForeignFunctionsFactory.DotExternalNodeGen::create);
-        add(ForeignFunctions.DotExternal2.class, ForeignFunctionsFactory.DotExternal2NodeGen::create);
-        add(ForeignFunctions.DotExternalGraphics.class, ForeignFunctionsFactory.DotExternalGraphicsNodeGen::create);
-        add(ForeignFunctions.Fortran.class, ForeignFunctionsFactory.FortranNodeGen::create);
         add(Formals.class, FormalsNodeGen::create);
         add(Format.class, FormatNodeGen::create);
         add(FormatC.class, FormatCNodeGen::create);
+        add(FortranAndCFunctions.DotC.class, FortranAndCFunctionsFactory.DotCNodeGen::create);
+        add(FortranAndCFunctions.Fortran.class, FortranAndCFunctionsFactory.FortranNodeGen::create);
         add(FrameFunctions.MatchCall.class, FrameFunctionsFactory.MatchCallNodeGen::create);
         add(FrameFunctions.ParentFrame.class, FrameFunctionsFactory.ParentFrameNodeGen::create);
         add(FrameFunctions.SysCall.class, FrameFunctionsFactory.SysCallNodeGen::create);
@@ -511,6 +511,7 @@ public class BasePackage extends RBuiltinPackage {
         add(MatMult.class, MatMult::create);
         add(Match.class, MatchNodeGen::create);
         add(MatchFun.class, MatchFunNodeGen::create);
+        add(MatchArg.class, MatchArgNodeGen::create);
         add(Matrix.class, MatrixNodeGen::create);
         add(Max.class, MaxNodeGen::create);
         add(Mean.class, MeanNodeGen::create);
@@ -556,6 +557,7 @@ public class BasePackage extends RBuiltinPackage {
         add(RawFunctions.CharToRaw.class, RawFunctionsFactory.CharToRawNodeGen::create);
         add(RawFunctions.RawToChar.class, RawFunctionsFactory.RawToCharNodeGen::create);
         add(RawFunctions.RawShift.class, RawFunctionsFactory.RawShiftNodeGen::create);
+        add(RawToBits.class, RawToBitsNodeGen::create);
         add(NumericalFunctions.Re.class, NumericalFunctionsFactory.ReNodeGen::create);
         add(ReadDCF.class, ReadDCFNodeGen::create);
         add(ReadREnviron.class, ReadREnvironNodeGen::create);
@@ -749,7 +751,7 @@ public class BasePackage extends RBuiltinPackage {
         addFastPath(baseFrame, "cbind", FastPathFactory.FORCED_EAGER_ARGS);
         addFastPath(baseFrame, "rbind", FastPathFactory.FORCED_EAGER_ARGS);
 
-        setContainsDispatch(baseFrame, "sys.function", "match.arg", "eval", "[.data.frame", "[[.data.frame", "[<-.data.frame", "[[<-.data.frame");
+        setContainsDispatch(baseFrame, "sys.function", "eval", "[.data.frame", "[[.data.frame", "[<-.data.frame", "[[<-.data.frame");
     }
 
     private static void setContainsDispatch(MaterializedFrame baseFrame, String... functions) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
index 8fc0691a76e82d5d36fbb142623805bb51e7f335..0a95c508e5ae397f7717df4e96528108cb1d0c27 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
@@ -36,6 +36,11 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode;
@@ -61,7 +66,6 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -95,6 +99,7 @@ public abstract class Bind extends RBaseNode {
     @Child private CastToVectorNode castVector;
     @Child private UseMethodInternalNode dcn;
     @Child private CastLogicalNode castLogical;
+    @Child private GetDimAttributeNode getDimsNode;
 
     private final BindType type;
 
@@ -103,7 +108,6 @@ public abstract class Bind extends RBaseNode {
     private final ConditionProfile allEmptyVectorProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile nonNullNames = BranchProfile.create();
     private final NACheck naCheck = NACheck.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     protected final ValueProfile resultProfile = ValueProfile.createClassProfile();
     protected final ValueProfile vectorProfile = ValueProfile.createClassProfile();
 
@@ -122,6 +126,14 @@ public abstract class Bind extends RBaseNode {
         this.type = type;
     }
 
+    protected int[] getVectorDimensions(RAbstractVector v) {
+        if (getDimsNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getDimsNode = insert(GetDimAttributeNode.create());
+        }
+        return getDimsNode.getDimensions(v);
+    }
+
     protected RAbstractVector castVector(Object value) {
         if (castVector == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -161,7 +173,8 @@ public abstract class Bind extends RBaseNode {
         }
     }
 
-    private Object bindInternal(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast) {
+    private Object bindInternal(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast, SetDimAttributeNode setDimNode,
+                    SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getDimNamesNode, GetNamesAttributeNode getNamesNode) {
         ArgumentsSignature signature = promiseArgs.getSignature();
         String[] vecNames = nullNamesProfile.profile(signature.getNonNullCount() == 0) ? null : new String[signature.getLength()];
         RAbstractVector[] vectors = new RAbstractVector[args.length];
@@ -217,46 +230,70 @@ public abstract class Bind extends RBaseNode {
             }
         }
         if (type == BindType.cbind) {
-            return genericCBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel);
+            return genericCBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
         } else {
-            return genericRBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel);
+            return genericRBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
         }
     }
 
     @Specialization(guards = {"precedence == LOGICAL_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allLogical(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
-                    @Cached("create()") CastLogicalNode cast) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true);
+                    @Cached("create()") CastLogicalNode cast,
+                    @Cached("create()") SetDimAttributeNode setDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
     }
 
     @Specialization(guards = {"precedence == INT_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allInt(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
-                    @Cached("create()") CastIntegerNode cast) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true);
+                    @Cached("create()") CastIntegerNode cast,
+                    @Cached("create()") SetDimAttributeNode setDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
     }
 
     @Specialization(guards = {"precedence == DOUBLE_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allDouble(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
-                    @Cached("create()") CastDoubleNode cast) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true);
+                    @Cached("create()") CastDoubleNode cast,
+                    @Cached("create()") SetDimAttributeNode setDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
     }
 
     @Specialization(guards = {"precedence == STRING_PRECEDENCE", "args.length> 1", "!isDataFrame(args)"})
     protected Object allString(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
-                    @Cached("create()") CastStringNode cast) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true);
+                    @Cached("create()") CastStringNode cast,
+                    @Cached("create()") SetDimAttributeNode setDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
     }
 
     @Specialization(guards = {"precedence == COMPLEX_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allComplex(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
-                    @Cached("create()") CastComplexNode cast) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true);
+                    @Cached("create()") CastComplexNode cast,
+                    @Cached("create()") SetDimAttributeNode setDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
     }
 
     @Specialization(guards = {"precedence == LIST_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allList(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
-                    @Cached("create()") CastListNode cast) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, false);
+                    @Cached("create()") CastListNode cast,
+                    @Cached("create()") SetDimAttributeNode setDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, false, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
     }
 
     /**
@@ -267,16 +304,16 @@ public abstract class Bind extends RBaseNode {
      * @param dimLength
      * @return dimnames
      */
-    protected Object getDimResultNamesFromElements(RAbstractVector vec, int dimLength, int dimInd) {
+    protected Object getDimResultNamesFromElements(RAbstractVector vec, int dimLength, int dimInd, GetDimNamesAttributeNode getDimNamesNode, GetNamesAttributeNode getNamesNode) {
         Object firstDimResultNames = RNull.instance;
         Object firstDimNames = RNull.instance;
         if (vec.isMatrix()) {
-            RList vecDimNames = vec.getDimNames(attrProfiles);
+            RList vecDimNames = getDimNamesNode.getDimNames(vec);
             if (vecDimNames != null) {
                 firstDimNames = vecDimNames.getDataAt(dimInd);
             }
-        } else if (!vec.isArray() || vec.getDimensions().length == 1) {
-            RStringVector names = vec.getNames(attrProfiles);
+        } else if (!vec.isArray() || getVectorDimensions(vec).length == 1) {
+            RStringVector names = getNamesNode.getNames(vec);
             firstDimNames = names == null ? RNull.instance : names;
         } else {
             RInternalError.unimplemented("binding multi-dimensional arrays is not supported");
@@ -295,11 +332,10 @@ public abstract class Bind extends RBaseNode {
      * by deparsing.
      */
     protected int getDimResultNamesFromVectors(RArgsValuesAndNames promiseArgs, RAbstractVector vec, String[] argNames, int resDim, int oldInd, int vecInd, int deparseLevel,
-                    String[] dimNamesArray,
-                    int dimNamesInd) {
+                    String[] dimNamesArray, int dimNamesInd, GetDimNamesAttributeNode getDimNamesNode) {
         int ind = oldInd;
         if (vec.isMatrix()) {
-            RList vecDimNames = vec.getDimNames(attrProfiles);
+            RList vecDimNames = getDimNamesNode.getDimNames(vec);
             if (vecDimNames != null) {
                 Object resDimNames = vecDimNames.getDataAt(dimNamesInd);
                 if (resDimNames != RNull.instance) {
@@ -319,7 +355,7 @@ public abstract class Bind extends RBaseNode {
                 dimNamesArray[ind++] = RRuntime.NAMES_ATTR_EMPTY_VALUE;
             }
             return -ind;
-        } else if (!vec.isArray() || vec.getDimensions().length == 1) {
+        } else if (!vec.isArray() || getVectorDimensions(vec).length == 1) {
             if (argNames == null) {
                 if (deparseLevel == 0) {
                     dimNamesArray[ind++] = RRuntime.NAMES_ATTR_EMPTY_VALUE;
@@ -377,9 +413,10 @@ public abstract class Bind extends RBaseNode {
     }
 
     protected int[] getDimensions(RAbstractVector vector) {
-        int[] dimensions = vector.getDimensions();
+        RAbstractVector vectorProfiled = vectorProfile.profile(vector);
+        int[] dimensions = getVectorDimensions(vectorProfiled);
         if (dimensions == null || dimensions.length != 2) {
-            return type == BindType.cbind ? new int[]{vector.getLength(), 1} : new int[]{1, vector.getLength()};
+            return type == BindType.cbind ? new int[]{vectorProfiled.getLength(), 1} : new int[]{1, vectorProfiled.getLength()};
         } else {
             assert dimensions.length == 2;
             return dimensions;
@@ -444,7 +481,9 @@ public abstract class Bind extends RBaseNode {
     private final BranchProfile everSeenNotEqualColumns = BranchProfile.create();
 
     @Specialization(guards = {"precedence != NO_PRECEDENCE", "args.length == 1"})
-    protected Object allOneElem(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) {
+    protected Object allOneElem(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
         RAbstractVector vec = castVector(args[0]);
         if (vec.isMatrix()) {
             return vec;
@@ -452,7 +491,10 @@ public abstract class Bind extends RBaseNode {
         int[] dims = getDimensions(vec);
         // for cbind dimNamesA is names for the 1st dim and dimNamesB is names for 2nd dim; for
         // rbind the other way around
-        Object dimNamesA = vec.getNames(attrProfiles) == null ? RNull.instance : vec.getNames(attrProfiles);
+        Object dimNamesA = getNamesNode.getNames(vec);
+        if (dimNamesA == null) {
+            dimNamesA = RNull.instance;
+        }
         Object dimNamesB;
 
         ArgumentsSignature signature = promiseArgs.getSignature();
@@ -473,17 +515,19 @@ public abstract class Bind extends RBaseNode {
         }
 
         RVector<?> res = (RVector<?>) vec.copyWithNewDimensions(dims);
-        res.setDimNames(RDataFactory.createList(type == BindType.cbind ? new Object[]{dimNamesA, dimNamesB} : new Object[]{dimNamesB, dimNamesA}));
+        setDimNamesNode.execute(res, RDataFactory.createList(type == BindType.cbind ? new Object[]{dimNamesA, dimNamesB} : new Object[]{dimNamesB, dimNamesA}));
         res.copyRegAttributesFrom(vec);
         return res;
     }
 
-    public RVector<?> genericCBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel) {
+    public RVector<?> genericCBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel,
+                    SetDimAttributeNode setDimNode, SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getDimNamesNode, GetNamesAttributeNode getNamesNode) {
 
         int[] resultDimensions = new int[2];
         int[] secondDims = new int[vectors.length];
         boolean notEqualRows = getResultDimensions(vectors, resultDimensions, secondDims);
-        RVector<?> result = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
+        RAbstractVector first = vectorProfile.profile(vectors[0]);
+        RVector<?> result = resultProfile.profile(first.createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
 
         int ind = 0;
         Object rowDimResultNames = RNull.instance;
@@ -494,11 +538,11 @@ public abstract class Bind extends RBaseNode {
             RAbstractVector vec = vectorProfile.profile(vectors[i]);
             if (rowDimResultNames == RNull.instance) {
                 // get the first valid names value
-                rowDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[0], 0);
+                rowDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[0], 0, getDimNamesNode, getNamesNode);
             }
 
             // compute dimnames for the second dimension
-            int newColInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, secondDims[i], colInd, i, deparseLevel, colDimNamesArray, 1);
+            int newColInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, secondDims[i], colInd, i, deparseLevel, colDimNamesArray, 1, getDimNamesNode);
             if (newColInd < 0) {
                 colInd = -newColInd;
             } else {
@@ -528,8 +572,8 @@ public abstract class Bind extends RBaseNode {
 
         }
         Object colDimResultNames = allColDimNamesNull ? RNull.instance : RDataFactory.createStringVector(colDimNamesArray, vecNamesComplete);
-        result.setDimensions(resultDimensions);
-        result.setDimNames(RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
+        setDimNode.setDimensions(result, resultDimensions);
+        setDimNamesNode.setDimNames(result, RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
         return result;
     }
 
@@ -558,7 +602,8 @@ public abstract class Bind extends RBaseNode {
         }
     }
 
-    public RVector<?> genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel) {
+    public RVector<?> genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel,
+                    SetDimAttributeNode setDimNode, SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getDimNamesNode, GetNamesAttributeNode getNamesNode) {
 
         int[] resultDimensions = new int[2];
         int[] firstDims = new int[vectors.length];
@@ -574,11 +619,11 @@ public abstract class Bind extends RBaseNode {
             RAbstractVector vec = vectorProfile.profile(vectors[i]);
             if (colDimResultNames == RNull.instance) {
                 // get the first valid names value
-                colDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[1], 1);
+                colDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[1], 1, getDimNamesNode, getNamesNode);
             }
 
             // compute dimnames for the second dimension
-            int newRowInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, firstDims[i], rowInd, i, deparseLevel, rowDimNamesArray, 0);
+            int newRowInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, firstDims[i], rowInd, i, deparseLevel, rowDimNamesArray, 0, getDimNamesNode);
             if (newRowInd < 0) {
                 rowInd = -newRowInd;
             } else {
@@ -613,8 +658,8 @@ public abstract class Bind extends RBaseNode {
 
         }
         Object rowDimResultNames = allRowDimNamesNull ? RNull.instance : RDataFactory.createStringVector(rowDimNamesArray, vecNamesComplete);
-        result.setDimensions(resultDimensions);
-        result.setDimNames(RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
+        setDimNode.setDimensions(result, resultDimensions);
+        setDimNamesNode.setDimNames(result, RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
         return result;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
index 431cc73c7dddd20f1860c4fa3b9c862136391f6c..99f09dcce3d563e95b0a3292e91bb7de0395d97e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
@@ -47,7 +47,8 @@ import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.CombineNodeGen.CombineInputCastNodeGen;
@@ -96,7 +97,6 @@ public abstract class Combine extends RBuiltinNode {
     @Child private CombineInputCast inputCast = CombineInputCastNodeGen.create(null);
     @Child private CastToVectorNode castVector;
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final BranchProfile naBranch = BranchProfile.create();
     private final NACheck naCheck = NACheck.create();
     private final ConditionProfile fastNamesMerge = ConditionProfile.createBinaryProfile();
@@ -127,7 +127,8 @@ public abstract class Combine extends RBuiltinNode {
                     @Cached("createCast(cachedPrecedence)") CastNode cast, //
                     @Cached("create()") BranchProfile naNameBranch, //
                     @Cached("create()") NACheck naNameCheck, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile) {
+                    @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
         CompilerAsserts.partialEvaluationConstant(cachedSignature);
         CompilerAsserts.partialEvaluationConstant(cachedPrecedence);
 
@@ -142,7 +143,8 @@ public abstract class Combine extends RBuiltinNode {
         // prepare the names (if there are any)
         boolean signatureHasNames = signatureHasNames(cachedSignature);
         CompilerAsserts.partialEvaluationConstant(signatureHasNames);
-        RStringVector namesVector = hasNamesProfile.profile(signatureHasNames || hasNames(elements)) ? foldNames(naNameBranch, naNameCheck, elements, size, cachedSignature) : null;
+        RStringVector namesVector = hasNamesProfile.profile(signatureHasNames || hasNames(elements, getNamesNode)) ? foldNames(naNameBranch, naNameCheck, elements, size, cachedSignature, getNamesNode)
+                        : null;
 
         // get the actual contents of the result
         RVector<?> result = foldContents(cachedPrecedence, elements, size, namesVector);
@@ -159,8 +161,9 @@ public abstract class Combine extends RBuiltinNode {
                     @Cached("createCast(cachedPrecedence)") CastNode cast, //
                     @Cached("create()") BranchProfile naNameBranch, //
                     @Cached("create()") NACheck naNameCheck, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile) {
-        return combineCached(args, false, args.getSignature(), cachedPrecedence, cast, naNameBranch, naNameCheck, hasNamesProfile);
+                    @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return combineCached(args, false, args.getSignature(), cachedPrecedence, cast, naNameBranch, naNameCheck, hasNamesProfile, getNamesNode);
     }
 
     @Specialization(guards = "recursive")
@@ -226,7 +229,7 @@ public abstract class Combine extends RBuiltinNode {
     }
 
     @ExplodeLoop
-    private boolean hasNames(Object[] elements) {
+    private boolean hasNames(Object[] elements, GetNamesAttributeNode getNamesNode) {
         for (int i = 0; i < elements.length; i++) {
             Object element = elements[i];
             if (i < argProfiles.length) {
@@ -234,7 +237,7 @@ public abstract class Combine extends RBuiltinNode {
             }
             if (element instanceof RAbstractVector) {
                 RAbstractVector vector = (RAbstractVector) element;
-                if (vector.getNames(attrProfiles) != null) {
+                if (getNamesNode.getNames(vector) != null) {
                     return true;
                 }
             }
@@ -243,7 +246,7 @@ public abstract class Combine extends RBuiltinNode {
     }
 
     @ExplodeLoop
-    private RStringVector foldNames(BranchProfile naNameBranch, NACheck naNameCheck, Object[] elements, int size, ArgumentsSignature signature) {
+    private RStringVector foldNames(BranchProfile naNameBranch, NACheck naNameCheck, Object[] elements, int size, ArgumentsSignature signature, GetNamesAttributeNode getNamesNode) {
         RStringVector result = RDataFactory.createStringVector(new String[size], true);
         result.incRefCount();
         int pos = 0;
@@ -252,18 +255,19 @@ public abstract class Combine extends RBuiltinNode {
             if (i < argProfiles.length) {
                 element = argProfiles[i].profile(element);
             }
-            pos += processNamesElement(naNameBranch, naNameCheck, result, pos, element, i, signature);
+            pos += processNamesElement(naNameBranch, naNameCheck, result, pos, element, i, signature, getNamesNode);
         }
         return result;
     }
 
-    private int processNamesElement(BranchProfile naNameBranch, NACheck naNameCheck, RStringVector result, int pos, Object element, int index, ArgumentsSignature signature) {
+    private int processNamesElement(BranchProfile naNameBranch, NACheck naNameCheck, RStringVector result, int pos, Object element, int index, ArgumentsSignature signature,
+                    GetNamesAttributeNode getNamesNode) {
         String signatureName = signature.getName(index);
         if (element instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) element;
             int length = v.getLength();
 
-            RStringVector newNames = v.getNames(attrProfiles);
+            RStringVector newNames = getNamesNode.getNames(v);
             if (signatureName != null && length > 0) {
                 if (fastNamesMerge.profile(length == 1 && newNames == null)) {
                     newNames = RDataFactory.createStringVector(new String[]{signatureName}, true);
@@ -455,6 +459,8 @@ public abstract class Combine extends RBuiltinNode {
     protected abstract static class CombineInputCast extends RNode {
 
         private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+        @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
+        @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
         public abstract Object execute(Object operand);
 
@@ -474,15 +480,13 @@ public abstract class Combine extends RBuiltinNode {
             RVector<?> materialized = vector.materialize();
             RVector<?> result = materialized.copyDropAttributes();
 
-            RStringVector vecNames = materialized.getInternalNames();
+            RStringVector vecNames = getNamesNode.getNames(materialized);
             if (hasNamesProfile.profile(vecNames != null)) {
                 result.initAttributes(RAttributesLayout.createNames(vecNames));
-                result.setInternalNames(vecNames);
             } else {
-                RList dimNames = materialized.getInternalDimNames();
+                RList dimNames = getDimNamesNode.getDimNames(materialized);
                 if (hasDimNamesProfile.profile(dimNames != null)) {
-                    result.initAttributes(RAttributesLayout.createDimNames(vecNames));
-                    result.setInternalDimNames(dimNames);
+                    result.initAttributes(RAttributesLayout.createDimNames(dimNames));
                 }
             }
             return result;
@@ -494,7 +498,7 @@ public abstract class Combine extends RBuiltinNode {
         }
 
         protected boolean needsCopy(RAbstractVector vector) {
-            return vector.getAttributes() != null || vector.getNames(attrProfiles) != null || vector.getDimNames(attrProfiles) != null;
+            return vector.getAttributes() != null || getNamesNode.getNames(vector) != null || getDimNamesNode.getDimNames(vector) != null;
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java
index bd91785573149dbf784c85774719cfbb211c6064..491c440ba79dbbd197522d28fb8ce694809b9ff9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CopyDFAttr.java
@@ -29,7 +29,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -37,12 +36,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 @RBuiltin(name = "copyDFattr", kind = INTERNAL, parameterNames = {"", ""}, behavior = COMPLEX)
 public abstract class CopyDFAttr extends RBuiltinNode {
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
     @Specialization()
     protected RAttributable copy(RAbstractContainer in, RAbstractVector out) {
         RVector<?> res = out.materialize();
         res.resetAllAttributes(false);
-        return res.copyAttributesFrom(attrProfiles, in);
+        return res.copyAttributesFrom(in);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
index 3aefffb5f6b5d7a8e3bc4f27c5d4f058c0e13fd1..9c6e521f08bfa375abdeec6ab6003d53c8d06ab0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
@@ -27,7 +27,11 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -62,21 +66,29 @@ public abstract class Crossprod extends RBuiltinNode {
     }
 
     @Specialization(guards = {"x.isMatrix()", "y.isMatrix()"})
-    protected RDoubleVector crossprod(RAbstractDoubleVector x, RAbstractDoubleVector y) {
-        int xRows = x.getDimensions()[0];
-        int xCols = x.getDimensions()[1];
-        int yRows = y.getDimensions()[0];
-        int yCols = y.getDimensions()[1];
-        return matMult.doubleMatrixMultiply(x, y, xCols, xRows, yRows, yCols, xRows, 1, 1, yRows, false);
+    protected RDoubleVector crossprod(RAbstractDoubleVector x, RAbstractDoubleVector y,
+                    @Cached("create()") GetDimAttributeNode getXDimsNode,
+                    @Cached("create()") GetDimAttributeNode getYDimsNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        int[] xDims = getXDimsNode.getDimensions(x);
+        int[] yDims = getYDimsNode.getDimensions(y);
+        int xRows = xDims[0];
+        int xCols = xDims[1];
+        int yRows = yDims[0];
+        int yCols = yDims[1];
+        return matMult.doubleMatrixMultiply(x, y, xCols, xRows, yRows, yCols, xRows, 1, 1, yRows, false, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
-    private static RDoubleVector mirror(RDoubleVector result) {
+    private static RDoubleVector mirror(RDoubleVector result, GetDimAttributeNode getResultDimsNode) {
         /*
          * Mirroring the result is not only good for performance, but it is also required to produce
          * the same result as GNUR.
          */
-        assert result.isMatrix() && result.getDimensions()[0] == result.getDimensions()[1];
-        int size = result.getDimensions()[0];
+        int[] resultDims = getResultDimsNode.getDimensions(result);
+        assert result.isMatrix() && resultDims[0] == resultDims[1];
+        int size = resultDims[0];
         double[] data = result.getDataWithoutCopying();
         for (int row = 0; row < size; row++) {
             int destIndex = row * size + row + 1;
@@ -96,10 +108,16 @@ public abstract class Crossprod extends RBuiltinNode {
     }
 
     @Specialization(guards = "x.isMatrix()")
-    protected RDoubleVector crossprodDoubleMatrix(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y) {
-        int xRows = x.getDimensions()[0];
-        int xCols = x.getDimensions()[1];
-        return mirror(matMult.doubleMatrixMultiply(x, x, xCols, xRows, xRows, xCols, xRows, 1, 1, xRows, true));
+    protected RDoubleVector crossprodDoubleMatrix(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y,
+                    @Cached("create()") GetDimAttributeNode getDimsNode,
+                    @Cached("create()") GetDimAttributeNode getResultDimsNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        int[] xDims = getDimsNode.getDimensions(x);
+        int xRows = xDims[0];
+        int xCols = xDims[1];
+        return mirror(matMult.doubleMatrixMultiply(x, x, xCols, xRows, xRows, xCols, xRows, 1, 1, xRows, true, setDimNamesNode, getADimNamesNode, getBDimNamesNode), getResultDimsNode);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java
index edf8441b58c47ee9bad392bd698d4bc1c72247d7..58cf95204c494529cf4eaff9eeb2710b2657b99c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMax.java
@@ -24,12 +24,12 @@ import java.util.Arrays;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RIntSequence;
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class CumMax extends RBuiltinNode {
 
     private final NACheck na = NACheck.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     @Override
     protected void createCasts(CastBuilder casts) {
@@ -96,7 +96,7 @@ public abstract class CumMax extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(cmaxV, i, cmaxV.length, RRuntime.DOUBLE_NA);
         }
-        return RDataFactory.createDoubleVector(cmaxV, na.neverSeenNA(), v.getNames(attrProfiles));
+        return RDataFactory.createDoubleVector(cmaxV, na.neverSeenNA(), getNamesNode.getNames(v));
     }
 
     @Specialization(contains = "cummaxIntSequence")
@@ -118,7 +118,7 @@ public abstract class CumMax extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(cmaxV, i, cmaxV.length, RRuntime.INT_NA);
         }
-        return RDataFactory.createIntVector(cmaxV, na.neverSeenNA(), v.getNames(attrProfiles));
+        return RDataFactory.createIntVector(cmaxV, na.neverSeenNA(), getNamesNode.getNames(v));
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java
index a1da7b792e40c8abb45fa505b7b76c03946a281f..b99ad15b12cf41a05b9bb5278ef605be97215766 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumMin.java
@@ -24,12 +24,12 @@ import java.util.Arrays;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RIntSequence;
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class CumMin extends RBuiltinNode {
 
     private final NACheck na = NACheck.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     @Override
     protected void createCasts(CastBuilder casts) {
@@ -96,7 +96,7 @@ public abstract class CumMin extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(cminV, i, cminV.length, RRuntime.DOUBLE_NA);
         }
-        return RDataFactory.createDoubleVector(cminV, na.neverSeenNA(), v.getNames(attrProfiles));
+        return RDataFactory.createDoubleVector(cminV, na.neverSeenNA(), getNamesNode.getNames(v));
     }
 
     @Specialization(contains = "cumminIntSequence")
@@ -118,7 +118,7 @@ public abstract class CumMin extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(cminV, i, cminV.length, RRuntime.INT_NA);
         }
-        return RDataFactory.createIntVector(cminV, na.neverSeenNA(), v.getNames(attrProfiles));
+        return RDataFactory.createIntVector(cminV, na.neverSeenNA(), getNamesNode.getNames(v));
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
index 56cda98a07fd8f9e13be1f2833356ff00be34526..254eaed5fb718f954495b90339e3955362a6ee0e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java
@@ -24,11 +24,11 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -45,7 +45,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class CumProd extends RBuiltinNode {
 
     private final NACheck na = NACheck.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     @Child private BinaryArithmetic mul = BinaryArithmetic.MULTIPLY.createOperation();
 
@@ -88,7 +88,7 @@ public abstract class CumProd extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(array, i, array.length, RRuntime.INT_NA);
         }
-        return RDataFactory.createIntVector(array, !na.neverSeenNA(), arg.getNames(attrProfiles));
+        return RDataFactory.createIntVector(array, !na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
     @Specialization
@@ -110,7 +110,7 @@ public abstract class CumProd extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(array, i, array.length, RRuntime.DOUBLE_NA);
         }
-        return RDataFactory.createDoubleVector(array, !na.neverSeenNA(), arg.getNames(attrProfiles));
+        return RDataFactory.createDoubleVector(array, !na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
     @Specialization
@@ -133,6 +133,6 @@ public abstract class CumProd extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(array, 2 * i, array.length, RRuntime.DOUBLE_NA);
         }
-        return RDataFactory.createComplexVector(array, !na.neverSeenNA(), arg.getNames(attrProfiles));
+        return RDataFactory.createComplexVector(array, !na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
index 06c1be88b75946797245a613f51c0f5a2578668a..3b6074626f3ab1dc0fc1aedf94739337cd75964d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java
@@ -36,11 +36,11 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -58,7 +58,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class CumSum extends RBuiltinNode {
 
     private final NACheck na = NACheck.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
 
@@ -100,7 +100,7 @@ public abstract class CumSum extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(res, i, res.length, RRuntime.INT_NA);
         }
-        return RDataFactory.createIntVector(res, na.neverSeenNA(), arg.getNames(attrProfiles));
+        return RDataFactory.createIntVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
     @Specialization
@@ -119,7 +119,7 @@ public abstract class CumSum extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(res, i, res.length, RRuntime.DOUBLE_NA);
         }
-        return RDataFactory.createDoubleVector(res, na.neverSeenNA(), arg.getNames(attrProfiles));
+        return RDataFactory.createDoubleVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
     @Specialization
@@ -141,7 +141,7 @@ public abstract class CumSum extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(res, i, res.length, RRuntime.INT_NA);
         }
-        return RDataFactory.createIntVector(res, na.neverSeenNA(), arg.getNames(attrProfiles));
+        return RDataFactory.createIntVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 
     @Specialization
@@ -161,6 +161,6 @@ public abstract class CumSum extends RBuiltinNode {
         if (!na.neverSeenNA()) {
             Arrays.fill(res, 2 * i, res.length, RRuntime.DOUBLE_NA);
         }
-        return RDataFactory.createComplexVector(res, na.neverSeenNA(), arg.getNames(attrProfiles));
+        return RDataFactory.createComplexVector(res, na.neverSeenNA(), getNamesNode.getNames(arg));
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
index c9a3e2826bcf8d325844e894e04922fb2c9f369a..c45cb05324403c8247e900ca5c64b8162defb836 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
@@ -36,7 +36,10 @@ import java.util.HashMap;
 import java.util.TimeZone;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -137,6 +140,7 @@ public class DatePOSIXFunctions {
     public abstract static class Date2POSIXlt extends RBuiltinNode {
 
         private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+        @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
         @Override
         protected void createCasts(CastBuilder casts) {
@@ -161,7 +165,7 @@ public class DatePOSIXFunctions {
                 }
             }
             RList result = builder.finish();
-            RStringVector xNames = x.getNames(attrProfiles);
+            RStringVector xNames = getNamesNode.getNames(x);
             if (xNames != null) {
                 ((RIntVector) result.getDataAt(5)).copyNamesFrom(attrProfiles, x);
             }
@@ -173,6 +177,7 @@ public class DatePOSIXFunctions {
     public abstract static class AsPOSIXlt extends RBuiltinNode {
 
         private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+        @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
         @Override
         protected void createCasts(CastBuilder casts) {
@@ -203,7 +208,7 @@ public class DatePOSIXFunctions {
                 }
             }
             RList result = builder.finish();
-            RStringVector xNames = x.getNames(attrProfiles);
+            RStringVector xNames = getNamesNode.getNames(x);
             if (xNames != null) {
                 ((RIntVector) result.getDataAt(5)).copyNamesFrom(attrProfiles, x);
             }
@@ -280,7 +285,8 @@ public class DatePOSIXFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected RDoubleVector posix2date(RAbstractListVector x) {
+        protected RDoubleVector posix2date(RAbstractListVector x,
+                        @Cached("create()") SetClassAttributeNode setClassAttrNode) {
             RAbstractVector secVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(0));
             RAbstractVector minVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(1));
             RAbstractVector hourVector = (RAbstractVector) RRuntime.asAbstractVector(x.getDataAt(2));
@@ -314,7 +320,7 @@ public class DatePOSIXFunctions {
                 }
             }
             RDoubleVector result = RDataFactory.createDoubleVector(data, complete);
-            result.setClassAttr(CLASS_ATTR);
+            setClassAttrNode.execute(result, CLASS_ATTR);
             return result;
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
index be4d0db5ec9a83264b3daeaf3390b780184ef2eb..95cb519bd8e14fe633c8a23426a03118a603379e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Dim.java
@@ -29,6 +29,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -40,9 +41,11 @@ public abstract class Dim extends RBuiltinNode {
 
     @Specialization
     protected Object dim(RAbstractContainer container, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasDimensionsProfile) {
-        if (hasDimensionsProfile.profile(container.hasDimensions())) {
-            return RDataFactory.createIntVector(container.getDimensions(), RDataFactory.COMPLETE_VECTOR);
+                    @Cached("createBinaryProfile()") ConditionProfile hasDimensionsProfile,
+                    @Cached("create()") GetDimAttributeNode getDimsNode) {
+        int[] dims = getDimsNode.getDimensions(container);
+        if (hasDimensionsProfile.profile(dims != null && dims.length > 0)) {
+            return RDataFactory.createIntVector(dims, RDataFactory.COMPLETE_VECTOR);
         } else {
             return RNull.instance;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
index 17661779644a7b819009377f238888db6a8a9fde..6953af8262f8466702d2e38fc0a2a5af330a1b52 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
@@ -26,11 +26,12 @@ import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
@@ -38,7 +39,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 @RBuiltin(name = "dimnames", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class DimNames extends RBuiltinNode {
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final ConditionProfile nullProfile = ConditionProfile.createBinaryProfile();
 
     @Specialization(guards = "!isRAbstractContainer(operand)")
@@ -47,8 +47,8 @@ public abstract class DimNames extends RBuiltinNode {
     }
 
     @Specialization
-    protected Object getDimNames(RAbstractContainer container) {
-        RList names = container.getDimNames(attrProfiles);
+    protected Object getDimNames(RAbstractContainer container, @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        RList names = getDimNamesNode.getDimNames(container);
         return nullProfile.profile(names == null) ? RNull.instance : names;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
index 7cb11a03f335315d7421134e3bb055a720266eed..dbcf174805a15697847c63c09643e27572a98e02 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
@@ -37,6 +37,7 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.FrameSlotNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen;
@@ -50,7 +51,6 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.REmpty;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -72,8 +72,8 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
 
     @Child private GetFunctions.Get getNode;
     @Child private GetCallerFrameNode getCallerFrame;
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final BranchProfile containsRLanguageProfile = BranchProfile.create();
     private final BranchProfile containsRSymbolProfile = BranchProfile.create();
 
@@ -113,7 +113,7 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
          * To re-create the illusion of a normal call, turn the values in argsAsList into promises.
          */
         Object[] argValues = argsAsList.getDataCopy();
-        RStringVector n = argsAsList.getNames(attrProfiles);
+        RStringVector n = getNamesNode.getNames(argsAsList);
         ArgumentsSignature signature;
         if (n == null) {
             signature = ArgumentsSignature.empty(argValues.length);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
index 43cfb6a97d7bde5e346af117e8b0e2762f640d5d..7104921f0dc2c92786597d31e9c707f6fadf5f1c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
@@ -25,9 +25,15 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
@@ -47,8 +53,13 @@ public abstract class Drop extends RBuiltinNode {
     private final ConditionProfile noDimNamesProfile = ConditionProfile.createBinaryProfile();
 
     @Specialization
-    protected RAbstractVector doDrop(RAbstractVector x) {
-        int[] dims = x.getDimensions();
+    protected RAbstractVector doDrop(RAbstractVector x,
+                    @Cached("create()") GetDimAttributeNode getDimsNode,
+                    @Cached("create()") SetDimAttributeNode setDimsNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimsNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimsNamesNode,
+                    @Cached("create()") SetNamesAttributeNode setNamesNode) {
+        int[] dims = getDimsNode.getDimensions(x);
         if (nullDimensions.profile(dims == null)) {
             return x;
         }
@@ -67,15 +78,15 @@ public abstract class Drop extends RBuiltinNode {
         if (resultIsScalarProfile.profile(lastNonOneIndex == -1)) {
             @SuppressWarnings("unused")
             RAbstractVector r = x.copy();
-            x.setDimensions(null);
-            x.setDimNames(null);
-            x.setNames(null);
+            setDimsNode.setDimensions(x, null);
+            setDimsNamesNode.setDimNames(x, null);
+            setNamesNode.setNames(x, null);
             return x;
         }
 
         // the result is vector
         if (resultIsVector.profile(newDimsLength <= 1)) {
-            return toVector(x, lastNonOneIndex);
+            return toVector(x, lastNonOneIndex, setDimsNode, getDimsNamesNode, setNamesNode);
         }
 
         // else: the result will be a matrix, copy non-1 dimensions
@@ -88,10 +99,10 @@ public abstract class Drop extends RBuiltinNode {
         }
 
         RAbstractVector result = x.copy();
-        result.setDimensions(newDims);
+        setDimsNode.setDimensions(result, newDims);
 
         // if necessary, copy corresponding dimnames
-        RList oldDimNames = x.getDimNames(dimNamesAttrProfile);
+        RList oldDimNames = getDimsNamesNode.getDimNames(x);
         if (noDimNamesProfile.profile(oldDimNames != null)) {
             newDimsIdx = 0;
             Object[] newDimNames = new Object[newDimsLength];
@@ -100,9 +111,9 @@ public abstract class Drop extends RBuiltinNode {
                     newDimNames[newDimsIdx++] = oldDimNames.getDataAt(i);
                 }
             }
-            result.setDimNames(RDataFactory.createList(newDimNames));
+            setDimsNamesNode.setDimNames(result, RDataFactory.createList(newDimNames));
         } else {
-            result.setDimNames(null);
+            setDimsNamesNode.setDimNames(result, null);
         }
 
         return result;
@@ -112,14 +123,14 @@ public abstract class Drop extends RBuiltinNode {
      * Handles the case when result is just a vector. The only catch is that we might have to copy
      * corresponding index from dimnames to names attribute of the new vector.
      */
-    private RAbstractVector toVector(RAbstractVector x, int nonOneIndex) {
+    private RAbstractVector toVector(RAbstractVector x, int nonOneIndex, SetDimAttributeNode setDimsNode, GetDimNamesAttributeNode getDimNamesNode, SetNamesAttributeNode setNamesNode) {
         RAbstractVector result = x.copy(); // share?
-        result.setDimensions(null);
+        setDimsNode.setDimensions(result, null);
 
         // copy dimnames to names if possible
-        RList dimNames = x.getDimNames(dimNamesAttrProfile);
+        RList dimNames = getDimNamesNode.getDimNames(x);
         if (noDimNamesProfile.profile(dimNames != null) && nonOneIndex < dimNames.getLength()) {
-            result.setNames(ensureStringVector(dimNames.getDataAt(nonOneIndex)));
+            setNamesNode.setNames(result, ensureStringVector(dimNames.getDataAt(nonOneIndex)));
         }
 
         return result;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
index 9edab7fbd30972db49f6a3a5f47d2996403c446e..943bd6ee74737e7f78df1db20db0fa42b51ab274 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
@@ -22,7 +22,11 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
@@ -32,6 +36,7 @@ import java.util.ArrayList;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -55,6 +60,8 @@ public class DynLoadFunctions {
 
     @RBuiltin(name = "dyn.load", visibility = OFF, kind = INTERNAL, parameterNames = {"lib", "local", "now", "unused"}, behavior = COMPLEX)
     public abstract static class DynLoad extends RBuiltinNode {
+        @Child private DLL.LoadPackageDLLNode loadPackageDLLNode = DLL.LoadPackageDLLNode.create();
+
         @Override
         protected void createCasts(CastBuilder casts) {
             casts.arg("lib").mustBe(stringValue()).asStringVector().mustBe(size(1), RError.Message.CHAR_ARGUMENT).findFirst();
@@ -67,7 +74,7 @@ public class DynLoadFunctions {
         @TruffleBoundary
         protected RList doDynLoad(String lib, boolean local, boolean now, @SuppressWarnings("unused") String unused) {
             try {
-                DLLInfo dllInfo = DLL.loadPackageDLL(lib, local, now);
+                DLLInfo dllInfo = loadPackageDLLNode.loadPackageDLL(lib, local, now);
                 return dllInfo.toRList();
             } catch (DLLException ex) {
                 // This is not a recoverable error
@@ -100,6 +107,9 @@ public class DynLoadFunctions {
 
     @RBuiltin(name = "getLoadedDLLs", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
     public abstract static class GetLoadedDLLs extends RBuiltinNode {
+
+        @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
+
         @Specialization
         @TruffleBoundary
         protected RList doGetLoadedDLLs() {
@@ -113,7 +123,7 @@ public class DynLoadFunctions {
                 data[i] = dllInfo.toRList();
             }
             RList result = RDataFactory.createList(data, RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR));
-            result.setClassAttr(RDataFactory.createStringVectorFromScalar(DLLINFOLIST_CLASS));
+            setClassAttrNode.execute(result, RDataFactory.createStringVectorFromScalar(DLLINFOLIST_CLASS));
             return result;
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
index e5ae35b08c784065f46fd10c6b38abd451044f51..d7188cf48b1d06d525c8c64352f9844d7f4d5d0c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
@@ -49,6 +49,8 @@ import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.RRootNode;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RList2EnvNode;
@@ -172,10 +174,14 @@ public class EnvFunctions {
             return list2Env.execute(list, env);
         }
 
+        protected GetFixedAttributeNode createGetXDataAttrNode() {
+            return GetFixedAttributeNode.create(RRuntime.DOT_XDATA);
+        }
+
         @Specialization
-        protected Object asEnvironment(RS4Object obj) {
+        protected Object asEnvironment(RS4Object obj, @Cached("createGetXDataAttrNode()") GetFixedAttributeNode getXDataAttrNode) {
             // generic dispatch tried already
-            Object xData = obj.getAttr(RRuntime.DOT_XDATA);
+            Object xData = getXDataAttrNode.execute(obj);
             if (xData == null || !(xData instanceof REnvironment)) {
                 throw RError.error(this, RError.Message.S4OBJECT_NX_ENVIRONMENT);
             } else {
@@ -319,8 +325,8 @@ public class EnvFunctions {
     @RBuiltin(name = "environment", kind = INTERNAL, parameterNames = {"fun"}, behavior = COMPLEX)
     public abstract static class Environment extends RBuiltinNode {
 
-        private static RAttributeProfiles attributeProfile = RAttributeProfiles.create();
         private final ConditionProfile attributable = ConditionProfile.createBinaryProfile();
+        @Child private GetFixedAttributeNode getEnvAttrNode;
 
         @Specialization
         protected Object environment(VirtualFrame frame, @SuppressWarnings("unused") RNull fun,
@@ -352,16 +358,24 @@ public class EnvFunctions {
         }
 
         @Specialization(guards = "isRFormula(formula)")
-        protected Object environment(RLanguage formula,
-                        @Cached("create()") RAttributeProfiles attrProfiles) {
-            Object result = formula.getAttr(attrProfiles, RRuntime.DOT_ENVIRONMENT);
+        protected Object environment(RLanguage formula) {
+            if (getEnvAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getEnvAttrNode = insert(GetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT));
+            }
+
+            Object result = getEnvAttrNode.execute(formula);
             return result == null ? RNull.instance : result;
         }
 
         @Specialization(guards = {"!isRNull(fun)", "!isRFunction(fun)", "!isRFormula(fun)"})
         protected Object environment(Object fun) {
             if (attributable.profile(fun instanceof RAttributable)) {
-                Object attr = ((RAttributable) fun).getAttr(attributeProfile, RRuntime.DOT_ENVIRONMENT);
+                if (getEnvAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    getEnvAttrNode = insert(GetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT));
+                }
+                Object attr = getEnvAttrNode.execute(fun);
                 return attr == null ? RNull.instance : attr;
             } else {
                 // Not an error according to GnuR
@@ -401,16 +415,22 @@ public class EnvFunctions {
             throw RError.error(this, RError.Message.USE_NULL_ENV_DEFUNCT);
         }
 
+        protected SetFixedAttributeNode createSetEnvAttrNode() {
+            return SetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT);
+        }
+
         @Specialization
         @TruffleBoundary
-        protected static Object updateEnvironment(RAbstractContainer obj, REnvironment env) {
-            return updateEnvironment((RAttributable) obj, env);
+        protected static Object updateEnvironment(RAbstractContainer obj, REnvironment env,
+                        @Cached("createSetEnvAttrNode()") SetFixedAttributeNode setEnvAttrNode) {
+            return updateEnvironment((RAttributable) obj, env, setEnvAttrNode);
         }
 
         @Specialization
         @TruffleBoundary
-        protected static Object updateEnvironment(RAttributable obj, REnvironment env) {
-            obj.setAttr(RRuntime.DOT_ENVIRONMENT, env);
+        protected static Object updateEnvironment(RAttributable obj, REnvironment env,
+                        @Cached("createSetEnvAttrNode()") SetFixedAttributeNode setEnvAttrNode) {
+            setEnvAttrNode.execute(obj, env);
             return obj;
         }
 
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 83bade1e3165ab0807caa023896b8a47890d2a4c..63d8b68047883562b4511b147b70663fb83c40ca 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
@@ -57,15 +57,16 @@ import java.util.stream.Stream;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 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.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBehavior;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
@@ -266,6 +267,8 @@ public class FileFunctions {
         private static final RStringVector NAMES_VECTOR = RDataFactory.createStringVector(NAMES, RDataFactory.COMPLETE_VECTOR);
         private static final RStringVector OCTMODE = RDataFactory.createStringVectorFromScalar("octmode");
 
+        @Child private SetClassAttributeNode setClassAttrNode;
+
         @Override
         protected void createCasts(CastBuilder casts) {
             casts.arg("extra_cols").asLogicalVector().findFirst().map(toBoolean());
@@ -400,12 +403,19 @@ public class FileFunctions {
             // @formatter:on
         }
 
-        private static Object createColumnResult(Column column, Object data, boolean complete) {
+        private Object createColumnResult(Column column, Object data, boolean complete) {
             // @formatter:off
             switch(column) {
                 case size: return RDataFactory.createDoubleVector((double[]) data, complete);
                 case isdir: return RDataFactory.createLogicalVector((byte[]) data, complete);
-                case mode: RIntVector res = RDataFactory.createIntVector((int[]) data, complete); res.setClassAttr(OCTMODE); return res;
+                case mode:
+                    if (setClassAttrNode == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        setClassAttrNode = insert(SetClassAttributeNode.create());
+                    }
+                    RIntVector res = RDataFactory.createIntVector((int[]) data, complete);
+                    setClassAttrNode.execute(res, OCTMODE);
+                    return res;
                 case mtime: case ctime: case atime:
                 case uid: case gid: return RDataFactory.createIntVector((int[]) data, complete);
                 case uname: case grname: return RDataFactory.createStringVector((String[]) data, complete);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
index 0ff9871785cb6fb0523d27ae4bae2b6f98f303e7..c69f2dac6af092d2932465d0d8d60fb9974cf2ee 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
@@ -15,7 +15,9 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
@@ -51,8 +53,10 @@ public abstract class FormatC extends RBuiltinNode {
 
     @SuppressWarnings("unused")
     @Specialization
-    RAttributable formatC(RAbstractContainer x, String mode, int width, int digits, String format, String flag, int iStrlen) {
+    RAttributable formatC(RAbstractContainer x, String mode, int width, int digits, String format, String flag, int iStrlen,
+                    @Cached("create()") SetClassAttributeNode setClassAttrNode) {
         RStringVector res = castStringVector(x);
-        return res.setClassAttr(null);
+        setClassAttrNode.reset(res);
+        return res;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
index fe7ce64eb662db796aae3d05ae6981247b57ea65..f873109da07b8215fc2cbf199541c0ec6dd8e2df 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
@@ -11,7 +11,8 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -26,6 +27,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 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.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -63,6 +65,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  */
 public class GrepFunctions {
     public abstract static class CommonCodeAdapter extends RBuiltinNode {
+        @Child protected PCRERFFI.PCRERFFINode pcreRFFINode = RFFIFactory.getRFFI().getPCRERFFI().createPCRERFFINode();
 
         /**
          * This profile is needed to satisfy API requirements.
@@ -205,8 +208,8 @@ public class GrepFunctions {
 
         protected PCRERFFI.Result compilePerlPattern(String pattern, boolean ignoreCase) {
             int cflags = ignoreCase ? PCRERFFI.CASELESS : 0;
-            long tables = RFFIFactory.getRFFI().getPCRERFFI().maketables();
-            PCRERFFI.Result pcre = RFFIFactory.getRFFI().getPCRERFFI().compile(pattern, cflags, tables);
+            long tables = pcreRFFINode.maketables();
+            PCRERFFI.Result pcre = pcreRFFINode.compile(pattern, cflags, tables);
             if (pcre.result == 0) {
                 // TODO output warning if pcre.errorMessage not NULL
                 throw RError.error(this, RError.Message.INVALID_REGEXP, pattern);
@@ -246,7 +249,7 @@ public class GrepFunctions {
                 for (int i = 0; i < len; i++) {
                     String text = vector.getDataAt(i);
                     if (!RRuntime.isNA(text)) {
-                        if (RFFIFactory.getRFFI().getPCRERFFI().exec(pcre.result, 0, text, 0, 0, ovector) >= 0) {
+                        if (pcreRFFINode.exec(pcre.result, 0, text, 0, 0, ovector) >= 0) {
                             matches[i] = true;
                         }
                     }
@@ -433,7 +436,7 @@ public class GrepFunctions {
                         int eflag = 0;
                         int lastEnd = -1;
                         StringBuffer sb = new StringBuffer();
-                        while (RFFIFactory.getRFFI().getPCRERFFI().exec(pcre.result, 0, input, offset, eflag, ovector) >= 0) {
+                        while (pcreRFFINode.exec(pcre.result, 0, input, offset, eflag, ovector) >= 0) {
                             nmatch++;
                             for (int j = offset; j < ovector[0]; j++) {
                                 sb.append(input.charAt(j));
@@ -472,7 +475,7 @@ public class GrepFunctions {
                     result[i] = value;
                 }
                 RStringVector ret = RDataFactory.createStringVector(result, vector.isComplete());
-                ret.copyAttributesFrom(attrProfiles, vector);
+                ret.copyAttributesFrom(vector);
                 return ret;
             } catch (PatternSyntaxException e) {
                 CompilerDirectives.transferToInterpreter();
@@ -663,6 +666,13 @@ public class GrepFunctions {
     @RBuiltin(name = "regexpr", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class Regexp extends CommonCodeAdapter {
 
+        @Child SetFixedAttributeNode setMatchLengthAttrNode = SetFixedAttributeNode.create("match.length");
+        @Child SetFixedAttributeNode setUseBytesAttrNode = SetFixedAttributeNode.create("useBytes");
+        @Child SetFixedAttributeNode setCaptureStartAttrNode = SetFixedAttributeNode.create("capture.start");
+        @Child SetFixedAttributeNode setCaptureLengthAttrNode = SetFixedAttributeNode.create("capture.length");
+        @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
+        @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
+
         @Override
         protected void createCasts(CastBuilder casts) {
             castPattern(casts);
@@ -754,19 +764,19 @@ public class GrepFunctions {
                 }
             }
             RIntVector ret = RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR);
-            ret.setAttr("match.length", RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
+            setMatchLengthAttrNode.execute(ret, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
             if (useBytes) {
-                ret.setAttr("useBytes", RRuntime.LOGICAL_TRUE);
+                setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE);
             }
             if (hasAnyCapture) {
                 RStringVector captureNamesVec = RDataFactory.createStringVector(captureNames, RDataFactory.COMPLETE_VECTOR);
                 RIntVector captureStartVec = RDataFactory.createIntVector(captureStart, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
-                captureStartVec.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
-                ret.setAttr("capture.start", captureStartVec);
+                setDimNamesAttrNode.execute(captureStartVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
+                setCaptureStartAttrNode.execute(ret, captureStartVec);
                 RIntVector captureLengthVec = RDataFactory.createIntVector(captureLength, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
-                captureLengthVec.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
-                ret.setAttr("capture.length", captureLengthVec);
-                ret.setAttr("capture.names", captureNamesVec);
+                setDimNamesAttrNode.execute(captureLengthVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
+                setCaptureLengthAttrNode.execute(ret, captureLengthVec);
+                setCaptureNamesAttrNode.execute(ret, captureNamesVec);
             }
             return ret;
         }
@@ -789,13 +799,13 @@ public class GrepFunctions {
                 }
             } else if (perl) {
                 PCRERFFI.Result pcre = compilePerlPattern(pattern, ignoreCase);
-                int maxCaptureCount = RFFIFactory.getRFFI().getPCRERFFI().getCaptureCount(pcre.result, 0);
+                int maxCaptureCount = pcreRFFINode.getCaptureCount(pcre.result, 0);
                 int[] ovector = new int[(maxCaptureCount + 1) * 3];
                 int offset = 0;
                 while (true) {
-                    int captureCount = RFFIFactory.getRFFI().getPCRERFFI().exec(pcre.result, 0, text, offset, 0, ovector);
+                    int captureCount = pcreRFFINode.exec(pcre.result, 0, text, offset, 0, ovector);
                     if (captureCount >= 0) {
-                        String[] captureNames = RFFIFactory.getRFFI().getPCRERFFI().getCaptureNames(pcre.result, 0, maxCaptureCount);
+                        String[] captureNames = pcreRFFINode.getCaptureNames(pcre.result, 0, maxCaptureCount);
                         for (int i = 0; i < captureNames.length; i++) {
                             if (captureNames[i] == null) {
                                 captureNames[i] = "";
@@ -844,6 +854,13 @@ public class GrepFunctions {
     @RBuiltin(name = "gregexpr", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class Gregexpr extends Regexp {
 
+        @Child SetFixedAttributeNode setMatchLengthAttrNode = SetFixedAttributeNode.create("match.length");
+        @Child SetFixedAttributeNode setUseBytesAttrNode = SetFixedAttributeNode.create("useBytes");
+        @Child SetFixedAttributeNode setCaptureStartAttrNode = SetFixedAttributeNode.create("capture.start");
+        @Child SetFixedAttributeNode setCaptureLengthAttrNode = SetFixedAttributeNode.create("capture.length");
+        @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
+        @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
+
         @Override
         protected void createCasts(CastBuilder casts) {
             castPattern(casts);
@@ -854,19 +871,19 @@ public class GrepFunctions {
             castUseBytes(casts);
         }
 
-        private static void setNoCaptureAttributes(RIntVector vec, RStringVector captureNames) {
+        private void setNoCaptureAttributes(RIntVector vec, RStringVector captureNames) {
             int len = captureNames.getLength();
             int[] captureStartData = new int[len];
             int[] captureLengthData = new int[len];
             Arrays.fill(captureStartData, -1);
             Arrays.fill(captureLengthData, -1);
             RIntVector captureStart = RDataFactory.createIntVector(captureStartData, RDataFactory.COMPLETE_VECTOR, new int[]{1, captureNames.getLength()});
-            captureStart.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
+            setDimNamesAttrNode.execute(captureStart, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
             RIntVector captureLength = RDataFactory.createIntVector(captureLengthData, RDataFactory.COMPLETE_VECTOR, new int[]{1, captureNames.getLength()});
-            captureLength.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
-            vec.setAttr("capture.start", captureStart);
-            vec.setAttr("capture.length", captureLength);
-            vec.setAttr("capture.names", captureNames);
+            setDimNamesAttrNode.execute(captureLength, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
+            setCaptureStartAttrNode.execute(vec, captureStart);
+            setCaptureLengthAttrNode.execute(vec, captureLength);
+            setCaptureNamesAttrNode.execute(vec, captureNames);
         }
 
         @Specialization
@@ -898,16 +915,16 @@ public class GrepFunctions {
                     for (int j = 0; j < txt.length(); j++) {
                         res.setDataAt(res.getDataWithoutCopying(), j, j + 1);
                     }
-                    res.setAttr("match.length", RDataFactory.createIntVector(txt.length()));
+                    setMatchLengthAttrNode.execute(res, RDataFactory.createIntVector(txt.length()));
                     if (useBytes) {
-                        res.setAttr("useBytes", RRuntime.LOGICAL_TRUE);
+                        setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
                     }
                 } else {
                     List<Info> l = getInfo(pattern, vector.getDataAt(i), ignoreCase, perl, fixed);
                     res = toIndexOrSizeVector(l, true);
-                    res.setAttr("match.length", toIndexOrSizeVector(l, false));
+                    setMatchLengthAttrNode.execute(res, toIndexOrSizeVector(l, false));
                     if (useBytes) {
-                        res.setAttr("useBytes", RRuntime.LOGICAL_TRUE);
+                        setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
                     }
                     RIntVector captureStart = toCaptureStartOrLength(l, true);
                     if (captureStart != null) {
@@ -922,9 +939,9 @@ public class GrepFunctions {
                             }
                         }
                         hasAnyCapture = true;
-                        res.setAttr("capture.start", captureStart);
-                        res.setAttr("capture.length", captureLength);
-                        res.setAttr("capture.names", captureNames);
+                        setCaptureStartAttrNode.execute(res, captureStart);
+                        setCaptureLengthAttrNode.execute(res, captureLength);
+                        setCaptureNamesAttrNode.execute(res, captureNames);
                     } else if (hasAnyCapture) {
                         assert captureNames != null;
                         // it's capture names from previous iteration, so copy
@@ -946,7 +963,7 @@ public class GrepFunctions {
             return RDataFactory.createIntVector(arr, RDataFactory.COMPLETE_VECTOR);
         }
 
-        private static RIntVector toCaptureStartOrLength(List<Info> list, boolean start) {
+        private RIntVector toCaptureStartOrLength(List<Info> list, boolean start) {
             assert list.size() > 0;
             Info firstInfo = list.get(0);
             if (!firstInfo.hasCapture) {
@@ -965,7 +982,7 @@ public class GrepFunctions {
                 }
             }
             RIntVector ret = RDataFactory.createIntVector(arr, RDataFactory.COMPLETE_VECTOR, new int[]{list.size(), firstInfo.captureNames.length});
-            ret.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, RDataFactory.createStringVector(firstInfo.captureNames, RDataFactory.COMPLETE_VECTOR)}));
+            setDimNamesAttrNode.execute(ret, RDataFactory.createList(new Object[]{RNull.instance, RDataFactory.createStringVector(firstInfo.captureNames, RDataFactory.COMPLETE_VECTOR)}));
             return ret;
         }
 
@@ -1152,7 +1169,7 @@ public class GrepFunctions {
             // treat split = NULL as split = ""
             RAbstractStringVector split = splitArg.getLength() == 0 ? RDataFactory.createStringVectorFromScalar("") : splitArg;
             String[] splits = new String[split.getLength()];
-            long pcreTables = perl ? RFFIFactory.getRFFI().getPCRERFFI().maketables() : 0;
+            long pcreTables = perl ? pcreRFFINode.maketables() : 0;
             PCRERFFI.Result[] pcreSplits = perl ? new PCRERFFI.Result[splits.length] : null;
 
             na.enable(x);
@@ -1161,7 +1178,7 @@ public class GrepFunctions {
                 splits[i] = fixed || perl ? split.getDataAt(i) : RegExp.checkPreDefinedClasses(split.getDataAt(i));
                 if (perl) {
                     if (!currentSplit.isEmpty()) {
-                        pcreSplits[i] = RFFIFactory.getRFFI().getPCRERFFI().compile(currentSplit, 0, pcreTables);
+                        pcreSplits[i] = pcreRFFINode.compile(currentSplit, 0, pcreTables);
                         if (pcreSplits[i].result == 0) {
                             // TODO output warning if pcre.errorMessage not NULL
                             throw RError.error(this, RError.Message.INVALID_REGEXP, currentSplit);
@@ -1231,14 +1248,14 @@ public class GrepFunctions {
             return RDataFactory.createStringVector(result, true);
         }
 
-        private static RStringVector splitPerl(String data, PCRERFFI.Result pcre) {
+        private RStringVector splitPerl(String data, PCRERFFI.Result pcre) {
             ArrayList<String> matches = new ArrayList<>();
             int lastEndOffset = 0;
             int lastEndIndex = 0;
             int[] ovector = new int[30];
             int[] fromByteMapping = getFromByteMapping(data); // non-null if it's necessary
 
-            while (RFFIFactory.getRFFI().getPCRERFFI().exec(pcre.result, 0, data, lastEndOffset, 0, ovector) >= 0) {
+            while (pcreRFFINode.exec(pcre.result, 0, data, lastEndOffset, 0, ovector) >= 0) {
                 // offset == byte position
                 // index == character position
                 int startOffset = ovector[0];
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
index 7b1275c1b1d5ffbe7a3539868b2d97a1a451e9a4..d04b57fd08082c853c5738796cd4fa9a5d2f151a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
@@ -27,6 +27,7 @@ import java.nio.ByteBuffer;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.MaterializedFrame;
@@ -35,6 +36,7 @@ import com.oracle.truffle.api.nodes.LoopNode;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
@@ -284,7 +286,8 @@ public class HiddenInternalFunctions {
 
         @Specialization(guards = "isDLLInfo(externalPtr)")
         @TruffleBoundary
-        protected RList getRegisteredRoutines(RExternalPtr externalPtr) {
+        protected RList getRegisteredRoutines(RExternalPtr externalPtr,
+                        @Cached("create()") SetClassAttributeNode setClassAttrNode) {
             Object[] data = new Object[NAMES.getLength()];
             DLL.DLLInfo dllInfo = (DLLInfo) externalPtr.getExternalObject();
             RInternalError.guarantee(dllInfo != null);
@@ -301,7 +304,7 @@ public class HiddenInternalFunctions {
                     symbolData[i] = symbolInfo.createRSymbolObject(rnt, true);
                 }
                 RList symbolDataList = RDataFactory.createList(symbolData);
-                symbolDataList.setClassAttr(NATIVE_ROUTINE_LIST);
+                setClassAttrNode.execute(symbolDataList, NATIVE_ROUTINE_LIST);
                 data[nst.ordinal()] = symbolDataList;
             }
             return RDataFactory.createList(data, NAMES);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
index 984935f3b56ac9def0cdc4c4fcc437aafa1d79a3..4a85c00052164f5c2ea76442cfab799fb2cdf6ea 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
@@ -31,11 +31,14 @@ 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.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -54,8 +57,11 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 public abstract class IsNA extends RBuiltinNode {
 
     @Child private IsNA recursiveIsNA;
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
+    @Child private GetDimAttributeNode getDimsNode = GetDimAttributeNode.create();
+    @Child private SetDimNamesAttributeNode setDimNamesNode = SetDimNamesAttributeNode.create();
+    @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final ConditionProfile nullDimNamesProfile = ConditionProfile.createBinaryProfile();
 
     private Object isNARecursive(Object o) {
@@ -194,10 +200,10 @@ public abstract class IsNA extends RBuiltinNode {
     }
 
     private RLogicalVector createResult(byte[] data, RAbstractVector originalVector) {
-        RLogicalVector result = RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR, originalVector.getDimensions(), originalVector.getNames(attrProfiles));
-        RList dimNames = originalVector.getDimNames(attrProfiles);
+        RLogicalVector result = RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR, getDimsNode.getDimensions(originalVector), getNamesNode.getNames(originalVector));
+        RList dimNames = getDimNamesNode.getDimNames(originalVector);
         if (nullDimNamesProfile.profile(dimNames != null)) {
-            result.setDimNames(dimNames);
+            setDimNamesNode.setDimNames(result, dimNames);
         }
         return result;
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index 2e1b049a8896038a9cfd8cd5c5286209590fed69..8d3ca0f3b4ef3d2c4cfe9763960769dca7ff01df 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -28,9 +28,16 @@ import java.util.function.Function;
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
@@ -49,6 +56,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
@@ -61,18 +69,22 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  */
 public class LaFunctions {
 
+    protected abstract static class Adapter extends RBuiltinNode {
+        @Child protected LapackRFFI.LapackRFFINode lapackRFFINode = RFFIFactory.getRFFI().getLapackRFFI().createLapackRFFINode();
+    }
+
     @RBuiltin(name = "La_version", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class Version extends RBuiltinNode {
+    public abstract static class Version extends Adapter {
         @Specialization
         @TruffleBoundary
         protected String doVersion() {
             int[] version = new int[3];
-            RFFIFactory.getRFFI().getLapackRFFI().ilaver(version);
+            lapackRFFINode.ilaver(version);
             return version[0] + "." + version[1] + "." + version[2];
         }
     }
 
-    private abstract static class RsgAdapter extends RBuiltinNode {
+    private abstract static class RsgAdapter extends Adapter {
         protected static final String[] NAMES = new String[]{"values", "vectors"};
         protected final BranchProfile errorProfile = BranchProfile.create();
 
@@ -90,8 +102,8 @@ public class LaFunctions {
         private final ConditionProfile hasComplexValues = ConditionProfile.createBinaryProfile();
 
         @Specialization
-        protected Object doRg(RDoubleVector matrix, boolean onlyValues) {
-            int[] dims = matrix.getDimensions();
+        protected Object doRg(RDoubleVector matrix, boolean onlyValues, @Cached("create()") GetDimAttributeNode getDimsNode) {
+            int[] dims = getDimsNode.getDimensions(matrix);
             // copy array component of matrix as Lapack destroys it
             int n = dims[0];
             double[] a = matrix.getDataCopy();
@@ -108,7 +120,7 @@ public class LaFunctions {
             double[] wi = new double[n];
             double[] work = new double[1];
             // ask for optimal size of work array
-            int info = RFFIFactory.getRFFI().getLapackRFFI().dgeev(jobVL, jobVR, n, a, n, wr, wi, left, n, right, n, work, -1);
+            int info = lapackRFFINode.dgeev(jobVL, jobVR, n, a, n, wr, wi, left, n, right, n, work, -1);
             if (info != 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dgeev");
@@ -116,7 +128,7 @@ public class LaFunctions {
             // now allocate work array and make the actual call
             int lwork = (int) work[0];
             work = new double[lwork];
-            info = RFFIFactory.getRFFI().getLapackRFFI().dgeev(jobVL, jobVR, n, a, n, wr, wi, left, n, right, n, work, lwork);
+            info = lapackRFFINode.dgeev(jobVL, jobVR, n, a, n, wr, wi, left, n, right, n, work, lwork);
             if (info != 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dgeev");
@@ -184,8 +196,8 @@ public class LaFunctions {
     @RBuiltin(name = "La_rs", kind = INTERNAL, parameterNames = {"matrix", "onlyValues"}, behavior = PURE)
     public abstract static class Rs extends RsgAdapter {
         @Specialization
-        protected Object doRs(RDoubleVector matrix, boolean onlyValues) {
-            int[] dims = matrix.getDimensions();
+        protected Object doRs(RDoubleVector matrix, boolean onlyValues, @Cached("create()") GetDimAttributeNode getDimsNode) {
+            int[] dims = getDimsNode.getDimensions(matrix);
             int n = dims[0];
             char jobv = onlyValues ? 'N' : 'V';
             char uplo = 'L';
@@ -209,7 +221,7 @@ public class LaFunctions {
             int[] isuppz = new int[2 * n];
             double[] work = new double[1];
             int[] iwork = new int[1];
-            int info = RFFIFactory.getRFFI().getLapackRFFI().dsyevr(jobv, range, uplo, n, x, n, vl, vu, il, iu, abstol, m, values, z, n, isuppz, work, lwork, iwork, liwork);
+            int info = lapackRFFINode.dsyevr(jobv, range, uplo, n, x, n, vl, vu, il, iu, abstol, m, values, z, n, isuppz, work, lwork, iwork, liwork);
             if (info != 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dysevr");
@@ -218,7 +230,7 @@ public class LaFunctions {
             liwork = iwork[0];
             work = new double[lwork];
             iwork = new int[liwork];
-            info = RFFIFactory.getRFFI().getLapackRFFI().dsyevr(jobv, range, uplo, n, x, n, vl, vu, il, iu, abstol, m, values, z, n, isuppz, work, lwork, iwork, liwork);
+            info = lapackRFFINode.dsyevr(jobv, range, uplo, n, x, n, vl, vu, il, iu, abstol, m, values, z, n, isuppz, work, lwork, iwork, liwork);
             if (info != 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dysevr");
@@ -239,7 +251,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_qr", kind = INTERNAL, parameterNames = {"in"}, behavior = PURE)
-    public abstract static class Qr extends RBuiltinNode {
+    public abstract static class Qr extends Adapter {
 
         @CompilationFinal private static final String[] NAMES = new String[]{"qr", "rank", "qraux", "pivot"};
 
@@ -251,13 +263,15 @@ public class LaFunctions {
         }
 
         @Specialization
-        protected RList doQr(RAbstractDoubleVector aIn) {
+        protected RList doQr(RAbstractDoubleVector aIn,
+                        @Cached("create()") GetDimAttributeNode getDimsNode,
+                        @Cached("create()") SetDimAttributeNode setDimsNode) {
             // This implementation is sufficient for B25 matcal-5.
             if (!(aIn instanceof RDoubleVector)) {
                 RError.nyi(this, "non-real vectors not supported (yet)");
             }
             RDoubleVector daIn = (RDoubleVector) aIn;
-            int[] dims = daIn.getDimensions();
+            int[] dims = getDimsNode.getDimensions(daIn);
             // copy array component of matrix as Lapack destroys it
             int n = dims[0];
             int m = dims[1];
@@ -266,14 +280,14 @@ public class LaFunctions {
             double[] tau = new double[m < n ? m : n];
             double[] work = new double[1];
             // ask for optimal size of work array
-            int info = RFFIFactory.getRFFI().getLapackRFFI().dgeqp3(m, n, a, m, jpvt, tau, work, -1);
+            int info = lapackRFFINode.dgeqp3(m, n, a, m, jpvt, tau, work, -1);
             if (info < 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dgeqp3");
             }
             int lwork = (int) work[0];
             work = new double[lwork];
-            info = RFFIFactory.getRFFI().getLapackRFFI().dgeqp3(m, n, a, m, jpvt, tau, work, lwork);
+            info = lapackRFFINode.dgeqp3(m, n, a, m, jpvt, tau, work, lwork);
             if (info < 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dgeqp3");
@@ -282,7 +296,7 @@ public class LaFunctions {
             // TODO check complete
             RDoubleVector ra = RDataFactory.createDoubleVector(a, RDataFactory.COMPLETE_VECTOR);
             // TODO check pivot
-            ra.setDimensions(dims);
+            setDimsNode.setDimensions(ra, dims);
             data[0] = ra;
             data[1] = m < n ? m : n;
             data[2] = RDataFactory.createDoubleVector(tau, RDataFactory.COMPLETE_VECTOR);
@@ -292,7 +306,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "qr_coef_real", kind = INTERNAL, parameterNames = {"q", "b"}, behavior = PURE)
-    public abstract static class QrCoefReal extends RBuiltinNode {
+    public abstract static class QrCoefReal extends Adapter {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
@@ -306,7 +320,9 @@ public class LaFunctions {
         }
 
         @Specialization
-        protected RDoubleVector doQrCoefReal(RList qIn, RDoubleVector bIn) {
+        protected RDoubleVector doQrCoefReal(RList qIn, RDoubleVector bIn,
+                        @Cached("create()") GetDimAttributeNode getBDimsNode,
+                        @Cached("create()") GetDimAttributeNode getQDimsNode) {
             // If bIn was coerced this extra copy is unnecessary
             RDoubleVector b = (RDoubleVector) bIn.copy();
 
@@ -315,8 +331,8 @@ public class LaFunctions {
             RDoubleVector tau = (RDoubleVector) qIn.getDataAt(2);
             int k = tau.getLength();
 
-            int[] bDims = bIn.getDimensions();
-            int[] qrDims = qr.getDimensions();
+            int[] bDims = getBDimsNode.getDimensions(bIn);
+            int[] qrDims = getQDimsNode.getDimensions(qr);
             int n = qrDims[0];
             if (bDims[0] != n) {
                 errorProfile.enter();
@@ -330,19 +346,19 @@ public class LaFunctions {
             // we work directly in the internal data of b
             double[] bData = b.getDataWithoutCopying();
             // ask for optimal size of work array
-            int info = RFFIFactory.getRFFI().getLapackRFFI().dormqr(SIDE, TRANS, n, nrhs, k, qrData, n, tauData, bData, n, work, -1);
+            int info = lapackRFFINode.dormqr(SIDE, TRANS, n, nrhs, k, qrData, n, tauData, bData, n, work, -1);
             if (info < 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dormqr");
             }
             int lwork = (int) work[0];
             work = new double[lwork];
-            info = RFFIFactory.getRFFI().getLapackRFFI().dormqr(SIDE, TRANS, n, nrhs, k, qrData, n, tauData, bData, n, work, lwork);
+            info = lapackRFFINode.dormqr(SIDE, TRANS, n, nrhs, k, qrData, n, tauData, bData, n, work, lwork);
             if (info < 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dormqr");
             }
-            info = RFFIFactory.getRFFI().getLapackRFFI().dtrtrs('U', 'N', 'N', k, nrhs, qrData, n, bData, n);
+            info = lapackRFFINode.dtrtrs('U', 'N', 'N', k, nrhs, qrData, n, bData, n);
             if (info < 0) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dtrtrs");
@@ -353,7 +369,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "det_ge_real", kind = INTERNAL, parameterNames = {"a", "uselog"}, behavior = PURE)
-    public abstract static class DetGeReal extends RBuiltinNode {
+    public abstract static class DetGeReal extends Adapter {
 
         private static final RStringVector NAMES_VECTOR = RDataFactory.createStringVector(new String[]{"modulus", "sign"}, RDataFactory.COMPLETE_VECTOR);
         private static final RStringVector DET_CLASS = RDataFactory.createStringVector(new String[]{"det"}, RDataFactory.COMPLETE_VECTOR);
@@ -363,6 +379,8 @@ public class LaFunctions {
         private final ConditionProfile doUseLog = ConditionProfile.createBinaryProfile();
         private final NACheck naCheck = NACheck.create();
 
+        @Child private SetFixedAttributeNode setLogAttrNode = SetFixedAttributeNode.create("logarithm");
+
         @Override
         protected void createCasts(CastBuilder casts) {
             //@formatter:off
@@ -379,14 +397,15 @@ public class LaFunctions {
         }
 
         @Specialization
-        protected RList doDetGeReal(RDoubleVector aIn, boolean useLog) {
+        protected RList doDetGeReal(RDoubleVector aIn, boolean useLog,
+                        @Cached("create()") GetDimAttributeNode getDimsNode) {
             RDoubleVector a = (RDoubleVector) aIn.copy();
-            int[] aDims = aIn.getDimensions();
+            int[] aDims = getDimsNode.getDimensions(aIn);
             int n = aDims[0];
             int[] ipiv = new int[n];
             double modulus = 0;
             double[] aData = a.getDataWithoutCopying();
-            int info = RFFIFactory.getRFFI().getLapackRFFI().dgetrf(n, n, aData, n, ipiv);
+            int info = lapackRFFINode.dgetrf(n, n, aData, n, ipiv);
             int sign = 1;
             if (info < 0) {
                 errorProfile.enter();
@@ -432,7 +451,7 @@ public class LaFunctions {
                 }
             }
             RDoubleVector modulusVec = RDataFactory.createDoubleVectorFromScalar(modulus);
-            modulusVec.setAttr("logarithm", RRuntime.asLogical(useLog));
+            setLogAttrNode.execute(modulusVec, RRuntime.asLogical(useLog));
             RList result = RDataFactory.createList(new Object[]{modulusVec, sign}, NAMES_VECTOR);
             RVector.setVectorClassAttr(result, DET_CLASS);
             return result;
@@ -440,11 +459,14 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_chol", kind = INTERNAL, parameterNames = {"a", "pivot", "tol"}, behavior = PURE)
-    public abstract static class LaChol extends RBuiltinNode {
+    public abstract static class LaChol extends Adapter {
 
         private final BranchProfile errorProfile = BranchProfile.create();
         private final ConditionProfile noPivot = ConditionProfile.createBinaryProfile();
 
+        @Child private SetFixedAttributeNode setPivotAttrNode = SetFixedAttributeNode.create("pivot");
+        @Child private SetFixedAttributeNode setRankAttrNode = SetFixedAttributeNode.create("rank");
+
         @Override
         protected void createCasts(CastBuilder casts) {
             //@formatter:off
@@ -464,9 +486,12 @@ public class LaFunctions {
         }
 
         @Specialization
-        protected RDoubleVector doDetGeReal(RDoubleVector aIn, boolean piv, double tol) {
+        protected RDoubleVector doDetGeReal(RDoubleVector aIn, boolean piv, double tol,
+                        @Cached("create()") GetDimAttributeNode getDimsNode,
+                        @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                        @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
             RDoubleVector a = (RDoubleVector) aIn.copy();
-            int[] aDims = aIn.getDimensions();
+            int[] aDims = getDimsNode.getDimensions(aIn);
             int n = aDims[0];
             int m = aDims[1];
             double[] aData = a.getDataWithoutCopying();
@@ -478,7 +503,7 @@ public class LaFunctions {
             }
             int info;
             if (noPivot.profile(!piv)) {
-                info = RFFIFactory.getRFFI().getLapackRFFI().dpotrf('U', m, aData, m);
+                info = lapackRFFINode.dpotrf('U', m, aData, m);
                 if (info != 0) {
                     errorProfile.enter();
                     // TODO informative error message (aka GnuR)
@@ -488,22 +513,22 @@ public class LaFunctions {
                 int[] ipiv = new int[m];
                 double[] work = new double[2 * m];
                 int[] rank = new int[1];
-                info = RFFIFactory.getRFFI().getLapackRFFI().dpstrf('U', n, aData, n, ipiv, rank, tol, work);
+                info = lapackRFFINode.dpstrf('U', n, aData, n, ipiv, rank, tol, work);
                 if (info != 0) {
                     errorProfile.enter();
                     // TODO informative error message (aka GnuR)
                     throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dpotrf");
                 }
-                a.setAttr("pivot", RRuntime.asLogical(piv));
-                a.setAttr("rank", rank[0]);
-                RList dn = a.getDimNames();
+                setPivotAttrNode.execute(a, RRuntime.asLogical(piv));
+                setRankAttrNode.execute(a, rank[0]);
+                RList dn = getDimNamesNode.getDimNames(a);
                 if (dn != null && dn.getDataAt(0) != null) {
                     Object[] dn2 = new Object[m];
                     // need to pivot the colnames
                     for (int i = 0; i < m; i++) {
                         dn2[i] = dn.getDataAt(ipiv[i] - 1);
                     }
-                    a.setDimNames(RDataFactory.createList(dn2));
+                    setDimNamesNode.setDimNames(a, RDataFactory.createList(dn2));
                 }
             }
             return a;
@@ -511,7 +536,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_solve", kind = INTERNAL, parameterNames = {"a", "bin", "tolin"}, behavior = PURE)
-    public abstract static class LaSolve extends RBuiltinNode {
+    public abstract static class LaSolve extends Adapter {
         protected final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
         @Child private CastDoubleNode castDouble = CastDoubleNodeGen.create(false, false, false);
 
@@ -535,8 +560,15 @@ public class LaFunctions {
         }
 
         @Specialization
-        protected RDoubleVector laSolve(RAbstractVector a, RDoubleVector bin, double tol) {
-            int[] aDims = a.getDimensions();
+        protected RDoubleVector laSolve(RAbstractVector a, RDoubleVector bin, double tol,
+                        @Cached("create()") GetDimAttributeNode getADimsNode,
+                        @Cached("create()") GetDimAttributeNode getBinDimsNode,
+                        @Cached("create()") SetDimAttributeNode setBDimsNode,
+                        @Cached("create()") SetDimNamesAttributeNode setBDimNamesNode,
+                        @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                        @Cached("create()") GetDimNamesAttributeNode getBinDimNamesNode,
+                        @Cached("create()") SetNamesAttributeNode setNamesNode) {
+            int[] aDims = getADimsNode.getDimensions(a);
             int n = aDims[0];
             if (n == 0) {
                 throw RError.error(this, RError.Message.GENERIC, "'a' is 0-diml");
@@ -545,12 +577,12 @@ public class LaFunctions {
             if (n2 != n) {
                 throw RError.error(this, RError.Message.MUST_BE_SQUARE, "a", n, n2);
             }
-            RList aDn = a.getDimNames(attrProfiles);
+            RList aDn = getADimNamesNode.getDimNames(a);
             int p;
             double[] bData;
             RDoubleVector b;
             if (bin.isMatrix()) {
-                int[] bDims = bin.getDimensions();
+                int[] bDims = getBinDimsNode.getDimensions(bin);
                 p = bDims[1];
                 if (p == 0) {
                     throw RError.error(this, RError.Message.GENERIC, "no right-hand side in 'b'");
@@ -561,8 +593,8 @@ public class LaFunctions {
                 }
                 bData = new double[n * p];
                 b = RDataFactory.createDoubleVector(bData, RDataFactory.COMPLETE_VECTOR);
-                b.setDimensions(new int[]{n, p});
-                RList binDn = bin.getDimNames();
+                setBDimsNode.setDimensions(b, new int[]{n, p});
+                RList binDn = getBinDimNamesNode.getDimNames(bin);
                 // This is somewhat odd, but Matrix relies on dropping NULL dimnames
                 if (aDn != null || binDn != null) {
                     // rownames(ans) = colnames(A), colnames(ans) = colnames(Bin)
@@ -574,7 +606,7 @@ public class LaFunctions {
                         bDnData[1] = binDn.getDataAt(1);
                     }
                     if (bDnData[0] != null || bDnData[1] != null) {
-                        b.setDimNames(RDataFactory.createList(bDnData));
+                        setBDimNamesNode.setDimNames(b, RDataFactory.createList(bDnData));
                     }
                 }
             } else {
@@ -585,7 +617,7 @@ public class LaFunctions {
                 bData = new double[n];
                 b = RDataFactory.createDoubleVector(bData, RDataFactory.COMPLETE_VECTOR);
                 if (aDn != null) {
-                    b.setNames(RDataFactory.createStringVector((String) aDn.getDataAt(1)));
+                    setNamesNode.setNames(b, RDataFactory.createStringVector((String) aDn.getDataAt(1)));
                 }
             }
 
@@ -601,7 +633,7 @@ public class LaFunctions {
                 assert aDouble != a;
                 avals = aDouble.getInternalStore();
             }
-            int info = RFFIFactory.getRFFI().getLapackRFFI().dgesv(n, p, avals, n, ipiv, bData, n);
+            int info = lapackRFFINode.dgesv(n, p, avals, n, ipiv, bData, n);
             if (info < 0) {
                 RError.error(this, RError.Message.LAPACK_INVALID_VALUE, -info, "dgesv");
             }
@@ -609,10 +641,10 @@ public class LaFunctions {
                 RError.error(this, RError.Message.LAPACK_EXACTLY_SINGULAR, "dgesv", info, info);
             }
             if (tol > 0) {
-                double anorm = RFFIFactory.getRFFI().getLapackRFFI().dlange('1', n, n, avals, n, null);
+                double anorm = lapackRFFINode.dlange('1', n, n, avals, n, null);
                 double[] work = new double[4 * n];
                 double[] rcond = new double[1];
-                RFFIFactory.getRFFI().getLapackRFFI().dgecon('1', n, avals, n, anorm, rcond, work, ipiv);
+                lapackRFFINode.dgecon('1', n, avals, n, anorm, rcond, work, ipiv);
                 if (rcond[0] < tol) {
                     RError.error(this, RError.Message.SYSTEM_COMP_SINGULAR, rcond[0]);
                 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
index a75fdbb515e1a6c46e2d4a92aedaf3d6a5d9a70a..54ecf0b6dc9db4eaf3fcfd74062c55e6372bb18c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNodeGen;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.LapplyNodeGen.LapplyInternalNodeGen;
@@ -45,7 +46,6 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -69,8 +69,6 @@ public abstract class Lapply extends RBuiltinNode {
 
     private static final Source CALL_SOURCE = RSource.fromTextInternal("FUN(X[[i]], ...)", RSource.Internal.LAPPLY);
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
     @Child private LapplyInternalNode lapply = LapplyInternalNodeGen.create();
 
     @Override
@@ -83,10 +81,10 @@ public abstract class Lapply extends RBuiltinNode {
     }
 
     @Specialization
-    protected Object lapply(VirtualFrame frame, RAbstractVector vec, RFunction fun) {
+    protected Object lapply(VirtualFrame frame, RAbstractVector vec, RFunction fun, @Cached("create()") GetNamesAttributeNode getNamesNode) {
         Object[] result = lapply.execute(frame, vec, fun);
         // set here else it gets overridden by the iterator evaluation
-        return RDataFactory.createList(result, vec.getNames(attrProfiles));
+        return RDataFactory.createList(result, getNamesNode.getNames(vec));
     }
 
     private static final class ExtractElementInternal extends RSourceSectionNode implements RSyntaxCall {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java
index 8532659c5be0afa030c0bac1a55a0e52f9406904..457eca9da958eace8975e6ec36c6fb2cd25d90ca 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java
@@ -32,6 +32,8 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
@@ -39,7 +41,6 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
@@ -80,7 +81,8 @@ public class LogFunctions {
         @Specialization
         protected RDoubleVector log(RAbstractIntVector vector, double base,
                         @Cached("create()") CopyOfRegAttributesNode copyAttrsNode,
-                        @Cached("create()") RAttributeProfiles attrProfiles) {
+                        @Cached("create()") GetNamesAttributeNode getNamesNode,
+                        @Cached("create()") GetDimAttributeNode getDimsNode) {
             double[] resultVector = new double[vector.getLength()];
             for (int i = 0; i < vector.getLength(); i++) {
                 int inputValue = vector.getDataAt(i);
@@ -90,13 +92,14 @@ public class LogFunctions {
                 }
                 resultVector[i] = result;
             }
-            return createResult(vector, resultVector, base, copyAttrsNode, attrProfiles);
+            return createResult(vector, resultVector, base, copyAttrsNode, getNamesNode, getDimsNode);
         }
 
         @Specialization
         protected RDoubleVector log(RAbstractDoubleVector vector, double base,
                         @Cached("create()") CopyOfRegAttributesNode copyAttrsNode,
-                        @Cached("create()") RAttributeProfiles attrProfiles) {
+                        @Cached("create()") GetNamesAttributeNode getNamesNode,
+                        @Cached("create()") GetDimAttributeNode getDimsNode) {
             double[] doubleVector = new double[vector.getLength()];
             for (int i = 0; i < vector.getLength(); i++) {
                 double value = vector.getDataAt(i);
@@ -105,7 +108,7 @@ public class LogFunctions {
                 }
                 doubleVector[i] = value;
             }
-            return createResult(vector, doubleVector, base, copyAttrsNode, attrProfiles);
+            return createResult(vector, doubleVector, base, copyAttrsNode, getNamesNode, getDimsNode);
         }
 
         private double logb(double x, double base) {
@@ -121,8 +124,9 @@ public class LogFunctions {
             return Math.log(x) / Math.log(base);
         }
 
-        private static RDoubleVector createResult(RAbstractVector source, double[] resultData, double base, CopyOfRegAttributesNode copyAttrsNode, RAttributeProfiles attrProfiles) {
-            RDoubleVector result = RDataFactory.createDoubleVector(resultData, source.isComplete() && !RRuntime.isNA(base), source.getDimensions(), source.getNames(attrProfiles));
+        private static RDoubleVector createResult(RAbstractVector source, double[] resultData, double base, CopyOfRegAttributesNode copyAttrsNode, GetNamesAttributeNode getNamesNode,
+                        GetDimAttributeNode getDimsNode) {
+            RDoubleVector result = RDataFactory.createDoubleVector(resultData, source.isComplete() && !RRuntime.isNA(base), getDimsNode.getDimensions(source), getNamesNode.getNames(source));
             copyAttrsNode.execute(source, result);
             return result;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java
index f363a88b079d661e0154ec885754984e446561d8..372547fa0f8364b32aa5a51ea702a98dcaeaae62 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mapply.java
@@ -37,6 +37,7 @@ import com.oracle.truffle.r.nodes.access.FrameSlotNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode.Mode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.MapplyNodeGen.MapplyInternalNodeGen;
@@ -49,7 +50,6 @@ import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
@@ -124,7 +124,7 @@ public abstract class Mapply extends RBuiltinNode {
             }
         }
 
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+        @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
         public abstract Object[] execute(VirtualFrame frame, RAbstractListVector dots, RFunction function, RAbstractListVector additionalArguments);
 
@@ -215,13 +215,13 @@ public abstract class Mapply extends RBuiltinNode {
             }
             Object[] values = new Object[dotsLength + moreArgsLength];
             String[] names = new String[dotsLength + moreArgsLength];
-            RStringVector dotsNames = dots.getNames(attrProfiles);
+            RStringVector dotsNames = getNames.getNames(dots);
             if (dotsNames != null) {
                 for (int listIndex = 0; listIndex < dotsLength; listIndex++) {
                     names[listIndex] = dotsNames.getDataAt(listIndex).isEmpty() ? null : dotsNames.getDataAt(listIndex);
                 }
             }
-            RStringVector moreArgsNames = moreArgs.getNames(attrProfiles);
+            RStringVector moreArgsNames = getNames.getNames(moreArgs);
             for (int listIndex = dotsLength; listIndex < dotsLength + moreArgsLength; listIndex++) {
                 values[listIndex] = moreArgs.getDataAt(listIndex - dotsLength);
                 names[listIndex] = moreArgsNames == null ? null : (moreArgsNames.getDataAt(listIndex - dotsLength).isEmpty() ? null : moreArgsNames.getDataAt(listIndex - dotsLength));
@@ -260,11 +260,11 @@ public abstract class Mapply extends RBuiltinNode {
         protected ElementNode[] createElementNodeArray(RAbstractListVector dots, RAbstractListVector moreArgs) {
             int length = dots.getLength() + moreArgs.getLength();
             ElementNode[] elementNodes = new ElementNode[length];
-            RStringVector dotsNames = dots.getNames(attrProfiles);
+            RStringVector dotsNames = getNames.getNames(dots);
             for (int i = 0; i < dots.getLength(); i++) {
                 elementNodes[i] = insert(new ElementNode(VECTOR_ELEMENT_PREFIX + (i + 1), dotsNames == null ? null : (dotsNames.getDataAt(i).isEmpty() ? null : dotsNames.getDataAt(i))));
             }
-            RStringVector moreArgsNames = moreArgs.getNames(attrProfiles);
+            RStringVector moreArgsNames = getNames.getNames(moreArgs);
             for (int i = dots.getLength(); i < dots.getLength() + moreArgs.getLength(); i++) {
                 elementNodes[i] = insert(new ElementNode(VECTOR_ELEMENT_PREFIX + (i + 1),
                                 moreArgsNames == null ? null : moreArgsNames.getDataAt(i - dots.getLength()).isEmpty() ? null : moreArgsNames.getDataAt(i - dots.getLength())));
@@ -289,14 +289,17 @@ public abstract class Mapply extends RBuiltinNode {
         }
 
         protected boolean sameNames(RAbstractListVector list, RAbstractListVector cachedList) {
-            if (list.getNames(attrProfiles) == null && cachedList.getNames(attrProfiles) == null) {
+            RStringVector listNames = getNames.getNames(list);
+            RStringVector cachedListNames = getNames.getNames(cachedList);
+            if (listNames == null && cachedListNames == null) {
                 return true;
-            } else if (list.getNames(attrProfiles) == null || cachedList.getNames(attrProfiles) == null) {
+            } else if (listNames == null || cachedListNames == null) {
                 return false;
             } else {
+
                 for (int i = 0; i < list.getLength(); i++) {
-                    String name = list.getNames(attrProfiles).getDataAt(i);
-                    String cachedName = cachedList.getNames(attrProfiles).getDataAt(i);
+                    String name = listNames.getDataAt(i);
+                    String cachedName = cachedListNames.getDataAt(i);
 
                     if (name == cachedName) {
                         continue;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
index c7a5ea146e47895dba8a926822b61db083c8c696..7bee0fa552fc045332ea15babf8bdaa0daca15f6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
@@ -34,12 +34,15 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.binary.BinaryMapArithmeticFunctionNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -71,10 +74,12 @@ public abstract class MatMult extends RBuiltinNode {
     private final ConditionProfile notOneRow = ConditionProfile.createBinaryProfile();
     private final ConditionProfile notOneColumn = ConditionProfile.createBinaryProfile();
 
-    private final RAttributeProfiles aDimAttributeProfile = RAttributeProfiles.create();
-    private final RAttributeProfiles bDimAttributeProfile = RAttributeProfiles.create();
     private final ConditionProfile noDimAttributes = ConditionProfile.createBinaryProfile();
 
+    @Child protected GetDimAttributeNode getADimsNode = GetDimAttributeNode.create();
+    @Child protected GetDimAttributeNode getBDimsNode = GetDimAttributeNode.create();
+    @Child protected SetDimAttributeNode setDimsNode = SetDimAttributeNode.create();
+
     protected abstract Object executeObject(Object a, Object b);
 
     private final NACheck na;
@@ -88,24 +93,26 @@ public abstract class MatMult extends RBuiltinNode {
         return MatMultNodeGen.create(true);
     }
 
-    @Specialization(guards = "bothZeroDim(a, b)")
+    @Specialization(guards = "bothZeroDim(a, b, getADimsNode, getBDimsNode)")
     protected RDoubleVector both0Dim(RAbstractDoubleVector a, RAbstractDoubleVector b) {
-        int r = b.getDimensions()[1];
-        int c = a.getDimensions()[0];
+        int r = getBDimsNode.getDimensions(b)[1];
+        int c = getADimsNode.getDimensions(a)[0];
         RDoubleVector result = RDataFactory.createDoubleVector(r * c);
-        result.setDimensions(new int[]{r, c});
+        setDimsNode.setDimensions(result, new int[]{r, c});
         return result;
     }
 
-    @Specialization(guards = "hasZeroDim(a)")
+    @Specialization(guards = "hasZeroDim(a, getADimsNode)")
     protected RAbstractVector left0Dim(RAbstractVector a, RAbstractVector b) {
-        int[] dim = a.getDimensions()[0] == 0 ? new int[]{0, b.getDimensions()[1]} : new int[]{b.getDimensions()[0], 0};
+        int[] aDim = getADimsNode.getDimensions(a);
+        int[] dim = aDim[0] == 0 ? new int[]{0, getBDimsNode.getDimensions(b)[1]} : new int[]{getBDimsNode.getDimensions(b)[0], 0};
         return a.copyWithNewDimensions(dim);
     }
 
-    @Specialization(guards = "hasZeroDim(b)")
+    @Specialization(guards = "hasZeroDim(b, getBDimsNode)")
     protected RAbstractVector right0Dim(RAbstractVector a, RAbstractVector b) {
-        int[] dim = b.getDimensions()[0] == 0 ? new int[]{0, a.getDimensions()[1]} : new int[]{a.getDimensions()[0], 0};
+        int[] bDim = getBDimsNode.getDimensions(b);
+        int[] dim = bDim[0] == 0 ? new int[]{0, getADimsNode.getDimensions(a)[1]} : new int[]{getADimsNode.getDimensions(a)[0], 0};
         return b.copyWithNewDimensions(dim);
     }
 
@@ -133,8 +140,9 @@ public abstract class MatMult extends RBuiltinNode {
     private final BranchProfile incompleteProfile = BranchProfile.create();
     @CompilationFinal private boolean seenLargeMatrix;
 
-    private RDoubleVector doubleMatrixMultiply(RAbstractDoubleVector a, RAbstractDoubleVector b, int aRows, int aCols, int bRows, int bCols) {
-        return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, 1, aRows, 1, bRows, false);
+    private RDoubleVector doubleMatrixMultiply(RAbstractDoubleVector a, RAbstractDoubleVector b, int aRows, int aCols, int bRows, int bCols, SetDimNamesAttributeNode setDimNamesNode,
+                    GetDimNamesAttributeNode getADimNamesNode, GetDimNamesAttributeNode getBDimNamesNode) {
+        return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, 1, aRows, 1, bRows, false, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     /**
@@ -155,7 +163,7 @@ public abstract class MatMult extends RBuiltinNode {
      * @return the result vector
      */
     public RDoubleVector doubleMatrixMultiply(RAbstractDoubleVector a, RAbstractDoubleVector b, int aRows, int aCols, int bRows, int bCols, int aRowStride, int aColStride, int bRowStride,
-                    int bColStride, boolean mirrored) {
+                    int bColStride, boolean mirrored, SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getADimNamesNode, GetDimNamesAttributeNode getBDimNamesNode) {
         if (aCols != bRows) {
             errorProfile.enter();
             throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
@@ -207,8 +215,8 @@ public abstract class MatMult extends RBuiltinNode {
         }
 
         RDoubleVector resultVec = RDataFactory.createDoubleVector(result, complete, new int[]{aRows, bCols});
-        RList aDimNames = a.getDimNames(aDimAttributeProfile);
-        RList bDimNames = b.getDimNames(bDimAttributeProfile);
+        RList aDimNames = getADimNamesNode.getDimNames(a);
+        RList bDimNames = getBDimNamesNode.getDimNames(b);
         if (!promoteDimNames || noDimAttributes.profile(aDimNames == null && bDimNames == null)) {
             return resultVec;
         }
@@ -220,7 +228,7 @@ public abstract class MatMult extends RBuiltinNode {
         if (bDimNames != null && bDimNames.getLength() > 1) {
             newDimsNames[1] = bDimNames.getDataAt(1);
         }
-        resultVec.setDimNames(RDataFactory.createList(newDimsNames));
+        setDimNamesNode.setDimNames(resultVec, RDataFactory.createList(newDimsNames));
         return resultVec;
     }
 
@@ -265,15 +273,19 @@ public abstract class MatMult extends RBuiltinNode {
     protected RDoubleVector multiply(RAbstractDoubleVector a, RAbstractDoubleVector b,
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
-                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals) {
+                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
         if (aIsMatrix.profile(a.isMatrix())) {
             if (bIsMatrix.profile(b.isMatrix())) {
-                int[] aDimensions = a.getDimensions();
-                int[] bDimensions = b.getDimensions();
-                return doubleMatrixMultiply(a, b, aDimensions[0], aDimensions[1], bDimensions[0], bDimensions[1]);
+                int[] aDimensions = getADimsNode.getDimensions(a);
+                int[] bDimensions = getBDimsNode.getDimensions(b);
+                return doubleMatrixMultiply(a, b, aDimensions[0], aDimensions[1], bDimensions[0], bDimensions[1], setDimNamesNode, getADimNamesNode, getBDimNamesNode);
             } else {
-                int aRows = a.getDimensions()[0];
-                int aCols = a.getDimensions()[1];
+                int[] aDim = getADimsNode.getDimensions(a);
+                int aRows = aDim[0];
+                int aCols = aDim[1];
                 int bRows;
                 int bCols;
                 if (lengthEquals.profile(aCols == b.getLength())) {
@@ -283,12 +295,13 @@ public abstract class MatMult extends RBuiltinNode {
                     bRows = 1;
                     bCols = b.getLength();
                 }
-                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols);
+                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
             }
         } else {
             if (bIsMatrix.profile(b.isMatrix())) {
-                int bRows = b.getDimensions()[0];
-                int bCols = b.getDimensions()[1];
+                int[] bDim = getBDimsNode.getDimensions(b);
+                int bRows = bDim[0];
+                int bCols = bDim[1];
                 int aRows;
                 int aCols;
                 if (lengthEquals.profile(bRows == a.getLength())) {
@@ -298,7 +311,7 @@ public abstract class MatMult extends RBuiltinNode {
                     aRows = a.getLength();
                     aCols = 1;
                 }
-                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols);
+                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
             } else {
                 if (a.getLength() != b.getLength()) {
                     errorProfile.enter();
@@ -328,14 +341,16 @@ public abstract class MatMult extends RBuiltinNode {
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix) {
         if (aIsMatrix.profile(a.isMatrix())) {
             if (bIsMatrix.profile(b.isMatrix())) {
-                final int aCols = a.getDimensions()[1];
-                final int bRows = b.getDimensions()[0];
+                int[] aDim = getADimsNode.getDimensions(a);
+                int[] bDim = getBDimsNode.getDimensions(b);
+                final int aCols = aDim[1];
+                final int bRows = bDim[0];
                 if (aCols != bRows) {
                     errorProfile.enter();
                     throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
                 }
-                final int aRows = a.getDimensions()[0];
-                final int bCols = b.getDimensions()[1];
+                final int aRows = aDim[0];
+                final int bCols = bDim[1];
                 double[] result = new double[(aRows * bCols) << 1];
                 na.enable(a);
                 na.enable(b);
@@ -353,8 +368,9 @@ public abstract class MatMult extends RBuiltinNode {
                 }
                 return RDataFactory.createComplexVector(result, na.neverSeenNA(), new int[]{aRows, bCols});
             } else {
-                final int aCols = a.getDimensions()[1];
-                final int aRows = a.getDimensions()[0];
+                int[] aDim = getADimsNode.getDimensions(a);
+                final int aCols = aDim[1];
+                final int aRows = aDim[0];
                 if (aCols != 1 && aCols != b.getLength()) {
                     errorProfile.enter();
                     throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
@@ -388,8 +404,9 @@ public abstract class MatMult extends RBuiltinNode {
             }
         } else {
             if (bIsMatrix.profile(b.isMatrix())) {
-                final int bRows = b.getDimensions()[0];
-                final int bCols = b.getDimensions()[1];
+                int[] bDim = getBDimsNode.getDimensions(b);
+                final int bRows = bDim[0];
+                final int bCols = bDim[1];
                 if (bRows != 1 && bRows != a.getLength()) {
                     errorProfile.enter();
                     throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
@@ -445,14 +462,16 @@ public abstract class MatMult extends RBuiltinNode {
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix) {
         if (aIsMatrix.profile(a.isMatrix())) {
             if (bIsMatrix.profile(b.isMatrix())) {
-                final int aCols = a.getDimensions()[1];
-                final int bRows = b.getDimensions()[0];
+                int[] aDim = getADimsNode.getDimensions(a);
+                int[] bDim = getBDimsNode.getDimensions(b);
+                final int aCols = aDim[1];
+                final int bRows = bDim[0];
                 if (aCols != bRows) {
                     errorProfile.enter();
                     throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
                 }
-                final int aRows = a.getDimensions()[0];
-                final int bCols = b.getDimensions()[1];
+                final int aRows = aDim[0];
+                final int bCols = bDim[1];
                 int[] result = new int[aRows * bCols];
                 na.enable(a);
                 na.enable(b);
@@ -468,8 +487,9 @@ public abstract class MatMult extends RBuiltinNode {
                 }
                 return RDataFactory.createIntVector(result, na.neverSeenNA(), new int[]{aRows, bCols});
             } else {
-                final int aCols = a.getDimensions()[1];
-                final int aRows = a.getDimensions()[0];
+                int[] aDim = getADimsNode.getDimensions(a);
+                final int aCols = aDim[1];
+                final int aRows = aDim[0];
                 if (aCols != 1 && aCols != b.getLength()) {
                     errorProfile.enter();
                     throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
@@ -500,9 +520,10 @@ public abstract class MatMult extends RBuiltinNode {
                 }
             }
         } else {
+            int[] bDim = getBDimsNode.getDimensions(b);
             if (bIsMatrix.profile(b.isMatrix())) {
-                final int bCols = b.getDimensions()[1];
-                final int bRows = b.getDimensions()[0];
+                final int bCols = bDim[1];
+                final int bRows = bDim[0];
                 if (bRows != 1 && bRows != a.getLength()) {
                     errorProfile.enter();
                     throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
@@ -622,32 +643,44 @@ public abstract class MatMult extends RBuiltinNode {
     protected RDoubleVector multiply(RAbstractIntVector a, RAbstractDoubleVector b,
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
-                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals) {
-        return multiply(RClosures.createIntToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals);
+                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(RClosures.createIntToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     @Specialization
     protected RDoubleVector multiply(RAbstractDoubleVector a, RAbstractIntVector b,
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
-                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals) {
-        return multiply(a, RClosures.createIntToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals);
+                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(a, RClosures.createIntToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     @Specialization
     protected RDoubleVector multiply(RAbstractLogicalVector a, RAbstractDoubleVector b,
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
-                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals) {
-        return multiply(RClosures.createLogicalToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals);
+                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(RClosures.createLogicalToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     @Specialization
     protected RDoubleVector multiply(RAbstractDoubleVector a, RAbstractLogicalVector b,
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
-                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals) {
-        return multiply(a, RClosures.createLogicalToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals);
+                    @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(a, RClosures.createLogicalToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     // errors
@@ -660,15 +693,16 @@ public abstract class MatMult extends RBuiltinNode {
 
     // guards
 
-    protected static boolean bothZeroDim(RAbstractVector a, RAbstractVector b) {
-        return hasZeroDim(a) && hasZeroDim(b);
+    protected static boolean bothZeroDim(RAbstractVector a, RAbstractVector b, GetDimAttributeNode getADimsNode, GetDimAttributeNode getBDimsNode) {
+        return hasZeroDim(a, getADimsNode) && hasZeroDim(b, getBDimsNode);
     }
 
-    protected static boolean hasZeroDim(RAbstractVector v) {
-        if (!v.hasDimensions()) {
+    protected static boolean hasZeroDim(RAbstractVector v, GetDimAttributeNode getDimsNode) {
+        int[] dims = getDimsNode.getDimensions(v);
+        if (dims == null || dims.length == 0) {
             return false;
         }
-        for (int d : v.getDimensions()) {
+        for (int d : dims) {
             if (d == 0) {
                 return true;
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc6405b87dad17cc3a56e2b301868c6686a84bbc
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base;
+
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
+import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
+import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.SUBSTITUTE;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.dsl.TypeSystemReference;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.RRootNode;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.MatchArgNodeGen.MatchArgInternalNodeGen;
+import com.oracle.truffle.r.nodes.function.FormalArguments;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.nodes.unary.CastNode;
+import com.oracle.truffle.r.runtime.RArguments;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPromise;
+import com.oracle.truffle.r.runtime.data.RTypes;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.nodes.RNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+
+@RBuiltin(name = "match.arg", kind = SUBSTITUTE, parameterNames = {"arg", "choices", "several.ok"}, nonEvalArgs = {0}, behavior = COMPLEX)
+public abstract class MatchArg extends RBuiltinNode {
+
+    @Override
+    public Object[] getDefaultParameterValues() {
+        return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
+    }
+
+    @TypeSystemReference(RTypes.class)
+    protected abstract static class MatchArgInternal extends Node {
+
+        @Child private PMatch pmatch = PMatchNodeGen.create();
+        @Child private Identical identical = IdenticalNodeGen.create();
+
+        @Children private final CastNode[] casts;
+
+        {
+            CastBuilder builder = new CastBuilder();
+            builder.arg(0).allowNull().asStringVector();
+            builder.arg(1).allowMissing().mustBe(stringValue()).asStringVector();
+            builder.arg(2).mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean());
+            this.casts = builder.getCasts();
+        }
+
+        public abstract Object execute(Object arg, Object choices, Object severalOK);
+
+        public final Object castAndExecute(Object arg, Object choices, Object severalOK) {
+            return execute(casts[0].execute(arg), casts[1].execute(choices), casts[2].execute(severalOK));
+        }
+
+        @Specialization
+        protected String matchArgNULL(@SuppressWarnings("unused") RNull arg, RAbstractStringVector choices, @SuppressWarnings("unused") boolean severalOK,
+                        @Cached("createBinaryProfile()") ConditionProfile isEmptyProfile) {
+            return isEmptyProfile.profile(choices.getLength() == 0) ? RRuntime.STRING_NA : choices.getDataAt(0);
+        }
+
+        private void checkEmpty(RAbstractStringVector choices, int count) {
+            if (count == 0) {
+                CompilerDirectives.transferToInterpreter();
+                StringBuilder choicesString = new StringBuilder();
+                for (int i = 0; i < choices.getLength(); i++) {
+                    choicesString.append(i == 0 ? "" : ", ").append(RRuntime.quoteString(choices.getDataAt(i), false));
+                }
+                throw RError.error(this, Message.ARG_ONE_OF, "arg", choicesString);
+            }
+        }
+
+        private static int count(RIntVector matched) {
+            int count = 0;
+            for (int i = 0; i < matched.getLength(); i++) {
+                if (matched.getDataAt(i) != -1) {
+                    count++;
+                }
+            }
+            return count;
+        }
+
+        @Specialization(guards = "!severalOK")
+        protected String matchArg(RAbstractStringVector arg, RAbstractStringVector choices, @SuppressWarnings("unused") boolean severalOK) {
+            if (identical.executeByte(arg, choices, true, true, true, true, true) == RRuntime.LOGICAL_TRUE) {
+                return choices.getDataAt(0);
+            }
+            if (arg.getLength() != 1) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(this, Message.MUST_BE_SCALAR, "arg");
+            }
+            RIntVector matched = pmatch.execute(arg, choices, -1, true);
+            int count = count(matched);
+            checkEmpty(choices, count);
+            if (count > 1) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(this, Message.MORE_THAN_ONE_MATCH, "match.arg");
+            }
+            return choices.getDataAt(matched.getDataAt(0) - 1);
+        }
+
+        @Specialization(guards = "severalOK")
+        protected Object matchArgSeveral(RAbstractStringVector arg, RAbstractStringVector choices, @SuppressWarnings("unused") boolean severalOK) {
+            if (arg.getLength() == 0) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(this, Message.MUST_BE_GE_ONE, "arg");
+            }
+            RIntVector matched = pmatch.execute(arg, choices, -1, true);
+            int count = count(matched);
+            if (count == 1) {
+                return choices.getDataAt(matched.getDataAt(0) - 1);
+            }
+            checkEmpty(choices, count);
+            String[] result = new String[count];
+            for (int i = 0; i < matched.getLength(); i++) {
+                result[i] = choices.getDataAt(matched.getDataAt(i) - 1);
+            }
+            return RDataFactory.createStringVector(result, choices.isComplete());
+        }
+    }
+
+    protected static final class MatchArgChoices extends Node {
+
+        private final CallTarget target;
+        private final String symbol;
+
+        @Child private RNode value;
+
+        public MatchArgChoices(VirtualFrame frame, RPromise arg) {
+            CompilerAsserts.neverPartOfCompilation();
+
+            RFunction function = RArguments.getFunction(frame);
+            assert function.getRBuiltin() == null;
+
+            this.symbol = arg.getClosure().asSymbol();
+            if (symbol == null) {
+                throw RError.error(this, Message.INVALID_USE, "match.arg");
+            }
+
+            RRootNode def = (RRootNode) function.getRootNode();
+            this.target = function.getTarget();
+            FormalArguments arguments = def.getFormalArguments();
+
+            for (int i = 0; i < arguments.getLength(); i++) {
+                assert symbol == arguments.getSignature().getName(i) || !symbol.equals(arguments.getSignature().getName(i));
+                if (symbol == arguments.getSignature().getName(i)) {
+                    RNode defaultArg = arguments.getDefaultArgument(i);
+                    if (defaultArg == null) {
+                        this.value = RContext.getASTBuilder().constant(RSyntaxNode.INTERNAL, RDataFactory.createEmptyStringVector()).asRNode();
+                    }
+                    this.value = RContext.getASTBuilder().process(defaultArg.asRSyntaxNode()).asRNode();
+                    return;
+                }
+            }
+            throw RError.error(RError.SHOW_CALLER, Message.INVALID_USE, "match.arg");
+        }
+
+        public boolean isSupported(VirtualFrame frame, RPromise arg) {
+            return RArguments.getFunction(frame).getTarget() == target && arg.getClosure().asSymbol() == symbol;
+        }
+
+        public Object execute(VirtualFrame frame) {
+            return value.execute(frame);
+        }
+    }
+
+    protected static MatchArgInternal createInternal() {
+        return MatchArgInternalNodeGen.create();
+    }
+
+    @Specialization(limit = "3", guards = "choicesValue.isSupported(frame, arg)")
+    protected Object matchArg(VirtualFrame frame, RPromise arg, @SuppressWarnings("unused") RMissing choices, Object severalOK,
+                    @Cached("new(frame, arg)") MatchArgChoices choicesValue,
+                    @Cached("createInternal()") MatchArgInternal internal,
+                    @Cached("new()") PromiseHelperNode promiseHelper) {
+        return internal.castAndExecute(promiseHelper.evaluate(frame, arg), choicesValue.execute(frame), severalOK);
+    }
+
+    protected static boolean isRMissing(Object value) {
+        return value instanceof RMissing;
+    }
+
+    @Specialization(guards = "!isRMissing(choices)")
+    protected Object matchArg(VirtualFrame frame, RPromise arg, Object choices, Object severalOK,
+                    @Cached("createInternal()") MatchArgInternal internal,
+                    @Cached("new()") PromiseHelperNode promiseHelper) {
+        return internal.castAndExecute(promiseHelper.evaluate(frame, arg), choices, severalOK);
+    }
+
+    @SuppressWarnings("unused")
+    @Fallback
+    protected Object matchArgFallback(Object arg, Object choices, Object severalOK) {
+        throw RError.error(this, Message.GENERIC, "too many different names in match.arg");
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
index bec8a180fab423d0887b7139cc7907743180d4a5..0895f7591631e6d7ef4c4630ecd35884c4923457 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java
@@ -28,8 +28,10 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -75,7 +77,8 @@ public abstract class Matrix extends RBuiltinNode {
     }
 
     @Specialization
-    protected RAbstractVector matrix(RAbstractVector data, int nrow, int ncol, boolean byrow, Object dimnames, boolean missingNr, boolean missingNc) {
+    protected RAbstractVector matrix(RAbstractVector data, int nrow, int ncol, boolean byrow, Object dimnames, boolean missingNr, boolean missingNc,
+                    @Cached("create()") SetDimAttributeNode setDimNode) {
         int[] dim;
         if (byrowProfile.profile(byrow)) {
             dim = computeDimByRow(data.getLength(), nrow, ncol, missingNr, missingNc);
@@ -99,7 +102,7 @@ public abstract class Matrix extends RBuiltinNode {
                 }
             } else {
                 res = data.createEmptySameType(0, RDataFactory.COMPLETE_VECTOR);
-                res.setDimensions(dim);
+                setDimNode.setDimensions(res, dim);
             }
         } else {
             res = data.copyResizedWithDimensions(dim, false);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
index 1f0a0a0deb44b0cb65f736923ed39858c624ab8f..c2faec1d69a4fca54a7103a68e8e3552c7ac485b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
@@ -33,11 +33,14 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -67,8 +70,11 @@ public abstract class NChar extends RBuiltinNode {
     @Specialization
     protected RIntVector ncharInt(RAbstractIntVector vector, String type, boolean allowNA, boolean keepNA,
                     @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
-                    @Cached("create()") RAttributeProfiles attrProfiles,
-                    @Cached("createBinaryProfile()") ConditionProfile nullDimNamesProfile) {
+                    @Cached("createBinaryProfile()") ConditionProfile nullDimNamesProfile,
+                    @Cached("create()") GetDimAttributeNode getDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
         int len = vector.getLength();
         int[] result = new int[len];
         loopProfile.profileCounted(len);
@@ -80,10 +86,10 @@ public abstract class NChar extends RBuiltinNode {
                 result[i] = (int) (Math.log10(x) + 1); // not the fastest one
             }
         }
-        RIntVector resultVector = RDataFactory.createIntVector(result, true, vector.getDimensions(), vector.getNames(attrProfiles));
-        RList dimNames = vector.getDimNames(attrProfiles);
+        RIntVector resultVector = RDataFactory.createIntVector(result, true, getDimNode.getDimensions(vector), getNamesNode.getNames(vector));
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (nullDimNamesProfile.profile(dimNames != null)) {
-            resultVector.setDimNames(dimNames);
+            setDimNamesNode.setDimNames(resultVector, dimNames);
         }
         return resultVector;
     }
@@ -92,18 +98,21 @@ public abstract class NChar extends RBuiltinNode {
     @Specialization
     protected RIntVector nchar(RAbstractStringVector vector, String type, boolean allowNA, boolean keepNA,
                     @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
-                    @Cached("create()") RAttributeProfiles attrProfiles,
-                    @Cached("createBinaryProfile()") ConditionProfile nullDimNamesProfile) {
+                    @Cached("createBinaryProfile()") ConditionProfile nullDimNamesProfile,
+                    @Cached("create()") GetDimAttributeNode getDimNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
         int len = vector.getLength();
         int[] result = new int[len];
         loopProfile.profileCounted(len);
         for (int i = 0; loopProfile.inject(i < len); i++) {
             result[i] = vector.getDataAt(i).length();
         }
-        RIntVector resultVector = RDataFactory.createIntVector(result, true, vector.getDimensions(), vector.getNames(attrProfiles));
-        RList dimNames = vector.getDimNames(attrProfiles);
+        RIntVector resultVector = RDataFactory.createIntVector(result, true, getDimNode.getDimensions(vector), getNamesNode.getNames(vector));
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (nullDimNamesProfile.profile(dimNames != null)) {
-            resultVector.setDimNames(dimNames);
+            setDimNamesNode.setDimNames(resultVector, dimNames);
         }
         return resultVector;
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java
index 91e6f763bcd36279b045cded3fa328d0a1cdf242..55c50f76361cc2080b1c84120370207135a03ece 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java
@@ -30,10 +30,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.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
@@ -41,12 +42,13 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 public abstract class Names extends RBuiltinNode {
 
     private final ConditionProfile hasNames = ConditionProfile.createBinaryProfile();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
     @Specialization
     protected Object getNames(RAbstractContainer container) {
-        if (hasNames.profile(container.getNames(attrProfiles) != null)) {
-            return container.getNames(attrProfiles);
+        RStringVector names = getNames.getNames(container);
+        if (hasNames.profile(names != null)) {
+            return names;
         } else {
             return RNull.instance;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java
index b955f976259a0570876ef29af61ae0c96e28c07f..072c6f76b689b375b95430309b4f2bc7bb0a64d0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NumericalFunctions.java
@@ -264,12 +264,12 @@ public class NumericalFunctions {
     public abstract static class Sign extends UnaryArithmeticBuiltinNode {
 
         public Sign() {
-            super(RType.Logical);
+            super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
         }
 
         @Override
         protected void createCasts(CastBuilder casts) {
-            casts.arg("x").defaultError(RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue());
+            casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue());
         }
 
         @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java
index f5487620db0fb63a21abd652f71710e0cf582d99..9486a8a9d9f6bde07fe95e17735384e70462fcb8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.MODIFIES_STATE;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java
index 4f841fb44d50e02358d9a6f652bc4736735e83ee..ad4cbd55f2405b4a34761c15835f1a5b45127e3f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMatch.java
@@ -43,6 +43,8 @@ public abstract class PMatch extends RBuiltinNode {
 
     private final ConditionProfile nomatchNA = ConditionProfile.createBinaryProfile();
 
+    public abstract RIntVector execute(RAbstractStringVector x, RAbstractStringVector table, int nomatch, boolean duplicatesOk);
+
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").asStringVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
index 8ac93354d9a2fdb4f9223c82978ee91a8110bf19..07a3c5f15a5a4458d230723f3b594788c05983c8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -96,6 +97,10 @@ public abstract class Parse extends RBuiltinNode {
     @Child private CastStringNode castStringNode;
     @Child private CastToVectorNode castVectorNode;
 
+    @Child private SetFixedAttributeNode setSrcRefAttrNode = SetFixedAttributeNode.create("srcref");
+    @Child private SetFixedAttributeNode setWholeSrcRefAttrNode = SetFixedAttributeNode.create("wholeSrcref");
+    @Child private SetFixedAttributeNode setSrcFileAttrNode = SetFixedAttributeNode.create("srcfile");
+
     @Override
     protected void createCasts(CastBuilder casts) {
         // Note: string is captured by the R wrapper and transformed to a file, other types not
@@ -219,7 +224,7 @@ public abstract class Parse extends RBuiltinNode {
         }
     }
 
-    private static void addAttributes(RExpression exprs, Source source, REnvironment srcFile) {
+    private void addAttributes(RExpression exprs, Source source, REnvironment srcFile) {
         Object[] srcrefData = new Object[exprs.getLength()];
         for (int i = 0; i < srcrefData.length; i++) {
             Object data = exprs.getDataAt(i);
@@ -239,7 +244,7 @@ public abstract class Parse extends RBuiltinNode {
             }
 
         }
-        exprs.setAttr("srcref", RDataFactory.createList(srcrefData));
+        setSrcRefAttrNode.execute(exprs, RDataFactory.createList(srcrefData));
         int[] wholeSrcrefData = new int[8];
         int endOffset = source.getCode().length() - 1;
         wholeSrcrefData[0] = source.getLineNumber(0);
@@ -248,8 +253,8 @@ public abstract class Parse extends RBuiltinNode {
         wholeSrcrefData[6] = wholeSrcrefData[0];
         wholeSrcrefData[6] = wholeSrcrefData[3];
 
-        exprs.setAttr("wholeSrcref", RDataFactory.createIntVector(wholeSrcrefData, RDataFactory.COMPLETE_VECTOR));
-        exprs.setAttr("srcfile", srcFile);
+        setWholeSrcRefAttrNode.execute(exprs, RDataFactory.createIntVector(wholeSrcrefData, RDataFactory.COMPLETE_VECTOR));
+        setSrcFileAttrNode.execute(exprs, srcFile);
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
index be182b91b23a5b1ef9147f6ae56359df1f2d456c..24496e3ae2d465157530b90cb0d3a2f76122ff08 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
@@ -27,6 +27,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -44,6 +45,8 @@ public abstract class ProcTime extends RBuiltinNode {
 
     private static RStringVector RNAMES;
 
+    @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
+
     @Specialization
     @TruffleBoundary
     protected RDoubleVector procTime() {
@@ -65,7 +68,8 @@ public abstract class ProcTime extends RBuiltinNode {
             RNAMES = RDataFactory.createStringVector(NAMES, RDataFactory.COMPLETE_VECTOR);
         }
         RDoubleVector result = RDataFactory.createDoubleVector(data, complete, RNAMES);
-        result.setClassAttr(PROC_TIME_CLASS);
+        setClassAttrNode.execute(result, PROC_TIME_CLASS);
+
         return result;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec205c198a4bf9870dc143127a22bf4188ece51a
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base;
+
+import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
+import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
+
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
+
+@RBuiltin(name = "rawToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
+public abstract class RawToBits extends RBuiltinNode {
+
+    @Override
+    protected void createCasts(CastBuilder casts) {
+        casts.arg("x").mustNotBeNull(RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x").mustBe(Predef.rawValue(), RError.SHOW_CALLER,
+                        RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x");
+    }
+
+    @Specialization
+    protected RAbstractRawVector rawToBits(RAbstractRawVector x) {
+        byte[] result = new byte[8 * x.getLength()];
+        int pos = 0;
+        for (int j = 0; j < x.getLength(); j++) {
+            byte temp = x.getRawDataAt(j);
+            for (int i = 0; i < 8; i++) {
+                result[pos++] = (byte) (temp & 1);
+                temp >>= 1;
+            }
+        }
+        return RDataFactory.createRawVector(result);
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
index 743d510865d5285d571a2fc60fcc33c6765e69e3..e89c2645f46e5482347b24152fbff85318ef7c3a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
@@ -37,14 +37,14 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -83,7 +83,7 @@ public abstract class Repeat extends RBuiltinNode {
     private final BranchProfile errorBranch = BranchProfile.create();
     private final ConditionProfile oneTimeGiven = ConditionProfile.createBinaryProfile();
     private final ConditionProfile replicateOnce = ConditionProfile.createBinaryProfile();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
     @Override
     public Object[] getDefaultParameterValues() {
@@ -106,7 +106,7 @@ public abstract class Repeat extends RBuiltinNode {
     }
 
     protected boolean hasNames(RAbstractVector x) {
-        return x.getNames(attrProfiles) != null;
+        return getNames.getNames(x) != null;
     }
 
     private RError invalidTimes() {
@@ -158,7 +158,7 @@ public abstract class Repeat extends RBuiltinNode {
             throw invalidTimes();
         }
         RAbstractVector input = handleEach(x, each);
-        RStringVector names = (RStringVector) handleEach(x.getNames(attrProfiles), each);
+        RStringVector names = (RStringVector) handleEach(getNames.getNames(x), each);
         RVector<?> r;
         if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) {
             names = (RStringVector) handleLengthOut(names, lengthOut, false);
@@ -168,7 +168,6 @@ public abstract class Repeat extends RBuiltinNode {
             r = handleTimes(input, times, false);
         }
         putNames.execute(initAttributes.execute(r), names);
-        r.setInternalNames(names);
         return r;
     }
 
@@ -179,14 +178,13 @@ public abstract class Repeat extends RBuiltinNode {
         RStringVector names;
         RVector<?> r;
         if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) {
-            names = (RStringVector) handleLengthOut(x.getNames(attrProfiles), lengthOut, true);
+            names = (RStringVector) handleLengthOut(getNames.getNames(x), lengthOut, true);
             r = handleLengthOut(x, lengthOut, true);
         } else {
-            names = (RStringVector) handleTimes(x.getNames(attrProfiles), times, true);
+            names = (RStringVector) handleTimes(getNames.getNames(x), times, true);
             r = handleTimes(x, times, true);
         }
         putNames.execute(initAttributes.execute(r), names);
-        r.setInternalNames(names);
         return r;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
index 7bd403ca3263119f4d7bf6c49f089da2d93b4ca8..d2407dfe625f4cda14649e91c61417c594371646 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
@@ -25,60 +25,35 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RPromise;
 
 /**
- * In the normal case, we are returning from the currently executing function, but in the case where
- * "return" was passed as an argument (promise) (e.g. in tryCatch) to a function, we will be
- * evaluating that in the context of a PromiseEvalFrame and the frame we need to return to is that
- * given by the PromiseEvalFrame.
+ * Return a value from the currently executing function, which is identified by the
+ * {@link RArguments#getCall(com.oracle.truffle.api.frame.Frame) call}. The return value will be
+ * delivered via a {@link ReturnException}, which is subsequently caught in the
+ * {@link FunctionDefinitionNode}.
  */
-@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, nonEvalArgs = {0}, behavior = COMPLEX)
+@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
 public abstract class Return extends RBuiltinNode {
 
     private final BranchProfile isPromiseEvalProfile = BranchProfile.create();
 
-    @Child private PromiseHelperNode promiseHelper;
-
-    private PromiseHelperNode initPromiseHelper() {
-        if (promiseHelper == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            promiseHelper = insert(new PromiseHelperNode());
-        }
-        return promiseHelper;
-    }
-
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RNull.instance};
     }
 
     @Specialization
-    protected Object returnFunction(VirtualFrame frame, @SuppressWarnings("unused") RMissing arg) {
-        throw new ReturnException(RNull.instance, RArguments.getCall(frame));
-    }
-
-    @Specialization
-    protected Object returnFunction(VirtualFrame frame, RNull arg) {
-        throw new ReturnException(arg, RArguments.getCall(frame));
-    }
-
-    @Specialization
-    protected Object returnFunction(VirtualFrame frame, RPromise expr) {
-        // Evaluate the result
-        Object value = initPromiseHelper().evaluate(frame, expr);
+    protected Object returnFunction(VirtualFrame frame, Object value) {
         RCaller call = RArguments.getCall(frame);
         while (call.isPromise()) {
             isPromiseEvalProfile.enter();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
index e6bce9fd7f17f5cd0f3016bc0a853fa078a1aa93..8a5488c18d78944eeb4a906301b760a75846ef0b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java
@@ -32,7 +32,6 @@ import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -55,7 +54,6 @@ public abstract class Round extends RBuiltinNode {
     @Child private RoundArithmetic roundOp = new RoundArithmetic();
 
     private final NACheck check = NACheck.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
 
     @Override
     public Object[] getDefaultParameterValues() {
@@ -124,7 +122,7 @@ public abstract class Round extends RBuiltinNode {
             result[i] = check.check(value) ? RRuntime.DOUBLE_NA : round(value, digits);
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(result, check.neverSeenNA());
-        ret.copyAttributesFrom(attrProfiles, x);
+        ret.copyAttributesFrom(x);
         return ret;
     }
 
@@ -137,7 +135,7 @@ public abstract class Round extends RBuiltinNode {
             result[i] = check.check(value) ? RRuntime.DOUBLE_NA : roundDigits(value, digits);
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(result, check.neverSeenNA());
-        ret.copyAttributesFrom(attrProfiles, x);
+        ret.copyAttributesFrom(x);
         return ret;
     }
 
@@ -165,7 +163,7 @@ public abstract class Round extends RBuiltinNode {
             check.check(r);
         }
         RComplexVector ret = RDataFactory.createComplexVector(result, check.neverSeenNA());
-        ret.copyAttributesFrom(attrProfiles, x);
+        ret.copyAttributesFrom(x);
         return ret;
     }
 
@@ -181,7 +179,7 @@ public abstract class Round extends RBuiltinNode {
             check.check(r);
         }
         RComplexVector ret = RDataFactory.createComplexVector(result, check.neverSeenNA());
-        ret.copyAttributesFrom(attrProfiles, x);
+        ret.copyAttributesFrom(x);
         return ret;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
index 6a4d2b0e3a599bbb0089d72d2dd6ae6b81277597..d9396a717a28d8f3084ab5a169a2ab44bc4fa0ac 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
@@ -31,18 +31,18 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.conn.RConnection;
 import com.oracle.truffle.r.runtime.conn.StdConnections;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDouble;
@@ -67,7 +67,7 @@ public abstract class Scan extends RBuiltinNode {
 
     private final NACheck naCheck = NACheck.create();
     private final BranchProfile errorProfile = BranchProfile.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
     @Child private CastToVectorNode castVector;
 
@@ -338,7 +338,7 @@ public abstract class Scan extends RBuiltinNode {
                 list.updateDataAt(i, vec.createEmptySameType(blockSize, RDataFactory.COMPLETE_VECTOR), null);
             }
         }
-        list.setNames(what.getNames(attrProfiles));
+        list.setNames(getNames.getNames(what));
 
         naCheck.enable(true);
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
index e318c352f9a7e3ded51e0bd78d06cfb50c9d1501..17a035de4a7ff78c82f6ecf809bc11439af6a064 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
@@ -31,12 +31,12 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.IntValueProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetRowNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -46,10 +46,11 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 public abstract class ShortRowNames extends RBuiltinNode {
 
     private final BranchProfile naValueMet = BranchProfile.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final BranchProfile errorProfile = BranchProfile.create();
     private final ValueProfile operandTypeProfile = ValueProfile.createClassProfile();
 
+    @Child private GetRowNamesAttributeNode getRowNamesNode = GetRowNamesAttributeNode.create();
+
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("type").asIntegerVector().findFirst().mustBe(gte0().and(lte(2)));
@@ -62,9 +63,9 @@ public abstract class ShortRowNames extends RBuiltinNode {
         Object operand = operandTypeProfile.profile(originalOperand);
         Object rowNames;
         if (operand instanceof RAbstractContainer) {
-            rowNames = ((RAbstractContainer) operand).getRowNames(attrProfiles);
+            rowNames = getRowNamesNode.getRowNames((RAbstractContainer) operand);
         } else if (operand instanceof REnvironment) {
-            rowNames = ((REnvironment) operand).getAttr(attrProfiles, RRuntime.ROWNAMES_ATTR_KEY);
+            rowNames = getRowNamesNode.execute(operand);
         } else {
             // for any other type GnuR returns 0
             return 0;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
index 08c9e57b8c1930c4216ba587f5665ef4a229bbc6..2a590e3749181816039b058a24c41352711c8f37 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
@@ -53,7 +53,8 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
-// transcribed from src/main/objects.c
+// transcribed from /src/library/methods/src/methods_list_dispatch.c (R_dispatch_generic function)
+
 @RBuiltin(name = "standardGeneric", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"f", "fdef"}, behavior = COMPLEX)
 public abstract class StandardGeneric extends RBuiltinNode {
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java
index 0313cad4b98aec16177b01b33fe7021ffa3fa6ee..31023607abacfbcd6dffea008880f47efebf75ec 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java
@@ -33,12 +33,13 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -52,9 +53,10 @@ public abstract class ToLowerOrUpper {
         private final VectorLengthProfile lengthProfile = VectorLengthProfile.create();
         private final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
         private final NACheck na = NACheck.create();
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+        @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
         @Child private CopyOfRegAttributesNode copyAttributes = CopyOfRegAttributesNodeGen.create();
+        @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create();
 
         private StringMapNode() {
             // nothing to do
@@ -82,7 +84,7 @@ public abstract class ToLowerOrUpper {
                 String value = vector.getDataAt(i);
                 stringVector[i] = elementFunction(value, i, function);
             }
-            RStringVector result = RDataFactory.createStringVector(stringVector, vector.isComplete(), vector.getDimensions(), vector.getNames(attrProfiles));
+            RStringVector result = RDataFactory.createStringVector(stringVector, vector.isComplete(), getDimNode.getDimensions(vector), getNames.getNames(vector));
             copyAttributes.execute(vector, result);
             return result;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
index ec945bb76c07a474ac8f40471b3ab7473c12b4d1..db8fcf308280a90a6933d6a4afd755b6a69584b6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
@@ -25,14 +25,14 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen;
-import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -50,7 +50,6 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 @RBuiltin(name = "t.default", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class Transpose extends RBuiltinNode {
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final BranchProfile hasDimNamesProfile = BranchProfile.create();
     private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile();
 
@@ -61,6 +60,7 @@ public abstract class Transpose extends RBuiltinNode {
     @Child private InitAttributesNode initAttributes = InitAttributesNode.create();
     @Child private SetFixedAttributeNode putDimensions = SetFixedAttributeNode.createDim();
     @Child private SetFixedAttributeNode putDimNames = SetFixedAttributeNode.createDimNames();
+    @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
     public abstract Object execute(RAbstractVector o);
 
@@ -96,15 +96,13 @@ public abstract class Transpose extends RBuiltinNode {
         copyRegAttributes.execute(vector, r);
         // set new dimensions
         int[] newDim = new int[]{secondDim, firstDim};
-        r.setInternalDimensions(newDim);
         putDimensions.execute(initAttributes.execute(r), RDataFactory.createIntVector(newDim, RDataFactory.COMPLETE_VECTOR));
         // set new dim names
-        RList dimNames = vector.getDimNames(attrProfiles);
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (dimNames != null) {
             hasDimNamesProfile.enter();
             assert dimNames.getLength() == 2;
             RList newDimNames = RDataFactory.createList(new Object[]{dimNames.getDataAt(1), dimNames.getDataAt(0)});
-            r.setInternalDimNames(newDimNames);
             putDimNames.execute(r.getAttributes(), newDimNames);
         }
         return r;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
index 03cf59487b7a937e378b58662b29d18458f38740..8558fef08d71acb5d113e9d833217db0c34a7f97 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java
@@ -22,6 +22,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.UnlistNodeGen.RecursiveLengthNodeGen;
@@ -31,7 +32,6 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -57,8 +57,7 @@ public abstract class Unlist extends RBuiltinNode {
     @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create();
     @Child private Length lengthNode;
     @Child private RecursiveLength recursiveLengthNode;
-
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
     @TypeSystemReference(RTypes.class)
     protected abstract static class RecursiveLength extends Node {
@@ -189,7 +188,8 @@ public abstract class Unlist extends RBuiltinNode {
             case PrecedenceNode.RAW_PRECEDENCE: {
                 byte[] result = new byte[totalSize];
                 if (!recursive) {
-                    RStringVector listNames = useNames && list.getNames(attrProfiles) != null ? list.getNames(attrProfiles) : null;
+                    RStringVector ln = getNames.getNames(list);
+                    RStringVector listNames = useNames && ln != null ? ln : null;
                     int position = 0;
                     for (int i = 0; i < list.getLength(); i++) {
                         if (list.getDataAt(i) != RNull.instance) {
@@ -204,7 +204,8 @@ public abstract class Unlist extends RBuiltinNode {
             case PrecedenceNode.LOGICAL_PRECEDENCE: {
                 byte[] result = new byte[totalSize];
                 if (!recursive) {
-                    RStringVector listNames = useNames && list.getNames(attrProfiles) != null ? list.getNames(attrProfiles) : null;
+                    RStringVector ln = getNames.getNames(list);
+                    RStringVector listNames = useNames && ln != null ? ln : null;
                     int position = 0;
                     for (int i = 0; i < list.getLength(); i++) {
                         if (list.getDataAt(i) != RNull.instance) {
@@ -220,7 +221,8 @@ public abstract class Unlist extends RBuiltinNode {
             case PrecedenceNode.INT_PRECEDENCE: {
                 int[] result = new int[totalSize];
                 if (!recursive) {
-                    RStringVector listNames = useNames && list.getNames(attrProfiles) != null ? list.getNames(attrProfiles) : null;
+                    RStringVector ln = getNames.getNames(list);
+                    RStringVector listNames = useNames && ln != null ? ln : null;
                     int position = 0;
                     for (int i = 0; i < list.getLength(); i++) {
                         if (list.getDataAt(i) != RNull.instance) {
@@ -236,7 +238,8 @@ public abstract class Unlist extends RBuiltinNode {
             case PrecedenceNode.DOUBLE_PRECEDENCE: {
                 double[] result = new double[totalSize];
                 if (!recursive) {
-                    RStringVector listNames = useNames && list.getNames(attrProfiles) != null ? list.getNames(attrProfiles) : null;
+                    RStringVector ln = getNames.getNames(list);
+                    RStringVector listNames = useNames && ln != null ? ln : null;
                     int position = 0;
                     for (int i = 0; i < list.getLength(); i++) {
                         if (list.getDataAt(i) != RNull.instance) {
@@ -252,7 +255,8 @@ public abstract class Unlist extends RBuiltinNode {
             case PrecedenceNode.COMPLEX_PRECEDENCE: {
                 double[] result = new double[totalSize << 1];
                 if (!recursive) {
-                    RStringVector listNames = useNames && list.getNames(attrProfiles) != null ? list.getNames(attrProfiles) : null;
+                    RStringVector ln = getNames.getNames(list);
+                    RStringVector listNames = useNames && ln != null ? ln : null;
                     int position = 0;
                     for (int i = 0; i < list.getLength(); i++) {
                         if (list.getDataAt(i) != RNull.instance) {
@@ -268,7 +272,8 @@ public abstract class Unlist extends RBuiltinNode {
             case PrecedenceNode.STRING_PRECEDENCE: {
                 String[] result = new String[totalSize];
                 if (!recursive) {
-                    RStringVector listNames = useNames && list.getNames(attrProfiles) != null ? list.getNames(attrProfiles) : null;
+                    RStringVector ln = getNames.getNames(list);
+                    RStringVector listNames = useNames && ln != null ? ln : null;
                     int position = 0;
                     for (int i = 0; i < list.getLength(); i++) {
                         if (list.getDataAt(i) != RNull.instance) {
@@ -285,7 +290,8 @@ public abstract class Unlist extends RBuiltinNode {
             case PrecedenceNode.EXPRESSION_PRECEDENCE: {
                 Object[] result = new Object[totalSize];
                 if (!recursive) {
-                    RStringVector listNames = useNames && list.getNames(attrProfiles) != null ? list.getNames(attrProfiles) : null;
+                    RStringVector ln = getNames.getNames(list);
+                    RStringVector listNames = useNames && ln != null ? ln : null;
                     int position = 0;
                     for (int i = 0; i < list.getLength(); i++) {
                         if (list.getDataAt(i) != RNull.instance) {
@@ -337,7 +343,8 @@ public abstract class Unlist extends RBuiltinNode {
 
         if (o instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) o;
-            RStringVector listNames = useNames && v.getNames(attrProfiles) != null ? v.getNames(attrProfiles) : null;
+            RStringVector ln = getNames.getNames(v);
+            RStringVector listNames = useNames && ln != null ? ln : null;
             for (int i = 0; i < v.getLength(); i++) {
                 String name = itemName(listNames, i);
                 Object cur = v.getDataAtAsObject(i);
@@ -373,7 +380,8 @@ public abstract class Unlist extends RBuiltinNode {
 
         if (o instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) o;
-            RStringVector listNames = useNames && v.getNames(attrProfiles) != null ? v.getNames(attrProfiles) : null;
+            RStringVector ln = getNames.getNames(v);
+            RStringVector listNames = useNames && ln != null ? ln : null;
             for (int i = 0; i < v.getLength(); i++) {
                 String name = itemName(listNames, i);
                 Object cur = v.getDataAtAsObject(i);
@@ -409,7 +417,8 @@ public abstract class Unlist extends RBuiltinNode {
 
         if (o instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) o;
-            RStringVector listNames = useNames && v.getNames(attrProfiles) != null ? v.getNames(attrProfiles) : null;
+            RStringVector ln = getNames.getNames(v);
+            RStringVector listNames = useNames && ln != null ? ln : null;
             for (int i = 0; i < v.getLength(); i++) {
                 String name = itemName(listNames, i);
                 Object cur = v.getDataAtAsObject(i);
@@ -445,7 +454,8 @@ public abstract class Unlist extends RBuiltinNode {
 
         if (o instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) o;
-            RStringVector listNames = useNames && v.getNames(attrProfiles) != null ? v.getNames(attrProfiles) : null;
+            RStringVector ln = getNames.getNames(v);
+            RStringVector listNames = useNames && ln != null ? ln : null;
             for (int i = 0; i < v.getLength(); i++) {
                 String name = itemName(listNames, i);
                 Object cur = v.getDataAtAsObject(i);
@@ -481,7 +491,8 @@ public abstract class Unlist extends RBuiltinNode {
 
         if (o instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) o;
-            RStringVector listNames = useNames && v.getNames(attrProfiles) != null ? v.getNames(attrProfiles) : null;
+            RStringVector ln = getNames.getNames(v);
+            RStringVector listNames = useNames && ln != null ? ln : null;
             for (int i = 0; i < v.getLength(); i++) {
                 String name = itemName(listNames, i);
                 Object cur = v.getDataAtAsObject(i);
@@ -522,7 +533,8 @@ public abstract class Unlist extends RBuiltinNode {
 
         if (o instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) o;
-            RStringVector listNames = useNames && v.getNames(attrProfiles) != null ? v.getNames(attrProfiles) : null;
+            RStringVector ln = getNames.getNames(v);
+            RStringVector listNames = useNames && ln != null ? ln : null;
             for (int i = 0; i < v.getLength(); i++) {
                 String name = itemName(listNames, i);
                 Object cur = v.getDataAtAsObject(i);
@@ -558,7 +570,8 @@ public abstract class Unlist extends RBuiltinNode {
 
         if (o instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) o;
-            RStringVector listNames = useNames && v.getNames(attrProfiles) != null ? v.getNames(attrProfiles) : null;
+            RStringVector ln = getNames.getNames(v);
+            RStringVector listNames = useNames && ln != null ? ln : null;
             for (int i = 0; i < v.getLength(); i++) {
                 String name = itemName(listNames, i);
                 Object cur = v.getDataAtAsObject(i);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
index 11bc95e938d5a7b6c2e3a9127e07b22fb9b2d582..34c1d680f8290eead7dfaabaed28894cabb35bd4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
@@ -34,6 +34,10 @@ 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.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetRowNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -66,6 +70,10 @@ public abstract class UpdateAttr extends RBuiltinNode {
     @Child private CastIntegerNode castInteger;
     @Child private CastToVectorNode castVector;
     @Child private CastListNode castList;
+    @Child private SetClassAttributeNode setClassAttrNode;
+    @Child private SetRowNamesAttributeNode setRowNamesAttrNode;
+    @Child private SetAttributeNode setGenAttrNode;
+    @Child private SetDimAttributeNode setDimNode;
 
     @CompilationFinal private String cachedName = "";
     @CompilationFinal private String cachedInternedName = "";
@@ -138,15 +146,28 @@ public abstract class UpdateAttr extends RBuiltinNode {
         RAbstractContainer result = (RAbstractContainer) container.getNonShared();
         // the name is interned, so identity comparison is sufficient
         if (internedName == RRuntime.DIM_ATTR_KEY) {
-            result.setDimensions(null);
+            if (setDimNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setDimNode = insert(SetDimAttributeNode.create());
+            }
+            setDimNode.setDimensions(result, null);
         } else if (internedName == RRuntime.NAMES_ATTR_KEY) {
             return updateNames(result, value);
         } else if (internedName == RRuntime.DIMNAMES_ATTR_KEY) {
             return updateDimNames(result, value);
         } else if (internedName == RRuntime.CLASS_ATTR_KEY) {
-            return (RAbstractContainer) result.setClassAttr(null);
+            if (setClassAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setClassAttrNode = insert(SetClassAttributeNode.create());
+            }
+            setClassAttrNode.reset(result);
+            return result;
         } else if (internedName == RRuntime.ROWNAMES_ATTR_KEY) {
-            result.setRowNames(null);
+            if (setRowNamesAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setRowNamesAttrNode = insert(SetRowNamesAttributeNode.create());
+            }
+            setRowNamesAttrNode.setRowNames(result, null);
         } else if (result.getAttributes() != null) {
             result.removeAttr(attrProfiles, internedName);
         }
@@ -175,18 +196,35 @@ public abstract class UpdateAttr extends RBuiltinNode {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.LENGTH_ZERO_DIM_INVALID);
             }
-            result.setDimensions(dimsVector.materialize().getDataCopy());
+            if (setDimNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setDimNode = insert(SetDimAttributeNode.create());
+            }
+            setDimNode.setDimensions(result, dimsVector.materialize().getDataCopy());
         } else if (internedName == RRuntime.NAMES_ATTR_KEY) {
             return updateNames(result, value);
         } else if (internedName == RRuntime.DIMNAMES_ATTR_KEY) {
             return updateDimNames(result, value);
         } else if (internedName == RRuntime.CLASS_ATTR_KEY) {
-            return (RAbstractContainer) result.setClassAttr(convertClassAttrFromObject(value));
+            if (setClassAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setClassAttrNode = insert(SetClassAttributeNode.create());
+            }
+            setClassAttrNode.execute(result, convertClassAttrFromObject(value));
+            return result;
         } else if (internedName == RRuntime.ROWNAMES_ATTR_KEY) {
-            result.setRowNames(castVector(value));
+            if (setRowNamesAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setRowNamesAttrNode = insert(SetRowNamesAttributeNode.create());
+            }
+            setRowNamesAttrNode.setRowNames(result, castVector(value));
         } else {
             // generic attribute
-            result.setAttr(internedName, value);
+            if (setGenAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setGenAttrNode = insert(SetAttributeNode.create());
+            }
+            setGenAttrNode.execute(result, internedName, value);
         }
 
         return result;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
index 31ce0f85a414a66a52bc6d3757e9398960508d74..4e0c99102cbac929b1bff3705111ca5f2e9f4f43 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
@@ -31,6 +31,10 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetRowNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -55,11 +59,15 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 public abstract class UpdateAttributes extends RBuiltinNode {
     private final ConditionProfile numAttributesProfile = ConditionProfile.createBinaryProfile();
     private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     @Child private UpdateNames updateNames;
     @Child private UpdateDimNames updateDimNames;
     @Child private CastIntegerNode castInteger;
     @Child private CastToVectorNode castVector;
+    @Child private SetAttributeNode setAttrNode;
+    @Child private SetDimAttributeNode setDimNode;
+    @Child private SetRowNamesAttributeNode setRowNamesNode;
 
     @Override
     protected void createCasts(CastBuilder casts) {
@@ -113,7 +121,7 @@ public abstract class UpdateAttributes extends RBuiltinNode {
 
     @Specialization
     protected RAbstractContainer updateAttributes(RAbstractContainer container, RList list) {
-        Object listNamesObject = list.getNames(attrProfiles);
+        Object listNamesObject = getNamesNode.getNames(list);
         if (listNamesObject == null || listNamesObject == RNull.instance) {
             throw RError.error(this, RError.Message.ATTRIBUTES_NAMED);
         }
@@ -154,28 +162,34 @@ public abstract class UpdateAttributes extends RBuiltinNode {
     }
 
     private void setDimAttribute(RAbstractContainer result, RList sourceList) {
-        RStringVector listNames = sourceList.getNames(attrProfiles);
+        RStringVector listNames = getNamesNode.getNames(sourceList);
         int length = sourceList.getLength();
         assert length > 0 : "Length should be > 0 for ExplodeLoop";
         for (int i = 0; i < sourceList.getLength(); i++) {
             Object value = sourceList.getDataAt(i);
             String attrName = listNames.getDataAt(i);
             if (attrName.equals(RRuntime.DIM_ATTR_KEY)) {
+
+                if (setDimNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    setDimNode = insert(SetDimAttributeNode.create());
+                }
+
                 if (value == RNull.instance) {
-                    result.setDimensions(null);
+                    setDimNode.setDimensions(result, null);
                 } else {
                     RAbstractIntVector dimsVector = castInteger(castVector(value));
                     if (dimsVector.getLength() == 0) {
                         throw RError.error(this, RError.Message.LENGTH_ZERO_DIM_INVALID);
                     }
-                    result.setDimensions(dimsVector.materialize().getDataCopy());
+                    setDimNode.setDimensions(result, dimsVector.materialize().getDataCopy());
                 }
             }
         }
     }
 
     private RAbstractContainer setRemainingAttributes(RAbstractContainer result, RList sourceList) {
-        RStringVector listNames = sourceList.getNames(attrProfiles);
+        RStringVector listNames = getNamesNode.getNames(sourceList);
         int length = sourceList.getLength();
         assert length > 0 : "Length should be > 0 for ExplodeLoop";
         RAbstractContainer res = result;
@@ -190,17 +204,26 @@ public abstract class UpdateAttributes extends RBuiltinNode {
                 res = updateDimNames(res, value);
             } else if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
                 if (value == RNull.instance) {
-                    res = (RAbstractContainer) result.setClassAttr(null);
+                    res.setClassAttr(null);
                 } else {
-                    res = (RAbstractContainer) result.setClassAttr(UpdateAttr.convertClassAttrFromObject(value));
+                    res.setClassAttr(UpdateAttr.convertClassAttrFromObject(value));
                 }
+                res = result;
             } else if (attrName.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
-                res.setRowNames(castVector(value));
+                if (setRowNamesNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    setRowNamesNode = insert(SetRowNamesAttributeNode.create());
+                }
+                setRowNamesNode.setRowNames(res, castVector(value));
             } else {
                 if (value == RNull.instance) {
                     res.removeAttr(attrProfiles, attrName);
                 } else {
-                    res.setAttr(attrName.intern(), value);
+                    if (setAttrNode == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        setAttrNode = insert(SetAttributeNode.create());
+                    }
+                    setAttrNode.execute(res, attrName.intern(), value);
                 }
             }
         }
@@ -251,6 +274,7 @@ public abstract class UpdateAttributes extends RBuiltinNode {
                 if (attrValue == null) {
                     throw RError.error(this, RError.Message.SET_INVALID_CLASS_ATTR);
                 }
+
                 attrObj.setClassAttr(UpdateAttr.convertClassAttrFromObject(attrValue));
             } else {
                 attrObj.setAttr(attrName.intern(), operand.getDataAt(i));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
index 62799507ade961086ec2c43d64c72aa344899b69..094f7fb3b8b052cc251da25e495c326f181a1cf3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
@@ -18,6 +18,8 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNodeGen;
@@ -48,6 +50,7 @@ public abstract class UpdateClass extends RBuiltinNode {
 
     @Child private CastTypeNode castTypeNode;
     @Child private TypeofNode typeof;
+    @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
 
     private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
 
@@ -61,7 +64,8 @@ public abstract class UpdateClass extends RBuiltinNode {
     @TruffleBoundary
     protected Object setClass(RAbstractContainer arg, @SuppressWarnings("unused") RNull className) {
         RAbstractContainer result = reuseNonShared(arg);
-        return result.setClassAttr(null);
+        setClassAttrNode.reset(result);
+        return result;
     }
 
     @Specialization(limit = "CACHE_LIMIT", guards = "cachedClassName == className")
@@ -94,6 +98,7 @@ public abstract class UpdateClass extends RBuiltinNode {
                 return setClass((RAbstractVector) result, RNull.instance);
             }
         }
+
         RAbstractContainer result = reuseNonShared(arg);
         if (result instanceof RAbstractVector) {
             RAbstractVector resultVector = (RAbstractVector) result;
@@ -114,73 +119,75 @@ public abstract class UpdateClass extends RBuiltinNode {
             }
         }
 
-        return result.setClassAttr(RDataFactory.createStringVector(className));
+        setClassAttrNode.execute(result, RDataFactory.createStringVector(className));
+        return result;
     }
 
     @Specialization
     @TruffleBoundary
     protected Object setClass(RAbstractContainer arg, RStringVector className) {
         RAbstractContainer result = reuseNonShared(arg);
-        return result.setClassAttr(className);
+        setClassAttrNode.execute(result, className);
+        return result;
     }
 
     @Specialization
     protected Object setClass(RFunction arg, RAbstractStringVector className) {
-        arg.setClassAttr(className.materialize());
+        setClassAttrNode.execute(arg, className.materialize());
         return arg;
     }
 
     @Specialization
     protected Object setClass(RFunction arg, @SuppressWarnings("unused") RNull className) {
-        arg.setClassAttr(null);
+        setClassAttrNode.reset(arg);
         return arg;
     }
 
     @Specialization
     protected Object setClass(REnvironment arg, RAbstractStringVector className) {
-        arg.setClassAttr(className.materialize());
+        setClassAttrNode.execute(arg, className.materialize());
         return arg;
     }
 
     @Specialization
     protected Object setClass(REnvironment arg, @SuppressWarnings("unused") RNull className) {
-        arg.setClassAttr(null);
+        setClassAttrNode.reset(arg);
         return arg;
     }
 
     @Specialization
     protected Object setClass(RSymbol arg, RAbstractStringVector className) {
-        arg.setClassAttr(className.materialize());
+        setClassAttrNode.execute(arg, className.materialize());
         return arg;
     }
 
     @Specialization
     protected Object setClass(RSymbol arg, @SuppressWarnings("unused") RNull className) {
-        arg.setClassAttr(null);
+        setClassAttrNode.reset(arg);
         return arg;
     }
 
     @Specialization
     protected Object setClass(RExternalPtr arg, RAbstractStringVector className) {
-        arg.setClassAttr(className.materialize());
+        setClassAttrNode.execute(arg, className.materialize());
         return arg;
     }
 
     @Specialization
     protected Object setClass(RExternalPtr arg, @SuppressWarnings("unused") RNull className) {
-        arg.setClassAttr(null);
+        setClassAttrNode.reset(arg);
         return arg;
     }
 
     @Specialization
     protected Object setClass(RS4Object arg, RAbstractStringVector className) {
-        arg.setClassAttr(className.materialize());
+        setClassAttrNode.execute(arg, className.materialize());
         return arg;
     }
 
     @Specialization
     protected Object setClass(RS4Object arg, @SuppressWarnings("unused") RNull className) {
-        arg.setClassAttr(null);
+        setClassAttrNode.reset(arg);
         return arg;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
index 0b7c49004d52e746b872d503f89b2e7fa32376aa..d30e638139ad629645041ed73dab870e8b043753 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
@@ -31,14 +31,12 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
+import com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -67,14 +65,13 @@ public abstract class UpdateDim extends RBuiltinNode {
     @Specialization
     protected RAbstractVector updateDim(RAbstractVector vector, RAbstractIntVector dimensions,
                     @Cached("createBinaryProfile()") ConditionProfile initAttrProfile,
-                    @Cached("createDim()") SetFixedAttributeNode putDimensions) {
+                    @Cached("createDim()") SetFixedAttributeNode putDimensions,
+                    @Cached("createNames()") RemoveFixedAttributeNode removeNames) {
         RIntVector dimensionsMaterialized = dimensions.materialize();
         int[] dimsData = dimensionsMaterialized.getDataCopy();
         RVector.verifyDimensions(vector.getLength(), dimsData, this);
         RVector<?> result = ((RAbstractVector) reuse.execute(vector)).materialize();
-        result.setInternalDimensions(dimsData);
-        result.setInternalNames(null);
-        result.setInternalDimNames(null);
+        removeNames.execute(result);
 
         DynamicObject attrs = result.getAttributes();
         if (initAttrProfile.profile(attrs == null)) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
index b5ee7967ce49f2b74af6722eca32380187520043..35adf33049ff8328091ce27e59d1947407474c8e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
@@ -31,7 +31,7 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
@@ -40,11 +40,8 @@ import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
@@ -54,7 +51,6 @@ public abstract class UpdateDimNames extends RBuiltinNode {
     protected static final String DIMNAMES_ATTR_KEY = RRuntime.DIMNAMES_ATTR_KEY;
 
     private final ConditionProfile shareListProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile isRVectorProfile = ConditionProfile.createBinaryProfile();
 
     @Child private CastStringNode castStringNode;
     @Child private CastToVectorNode castVectorNode;
@@ -96,15 +92,7 @@ public abstract class UpdateDimNames extends RBuiltinNode {
     protected RAbstractContainer updateDimnamesNull(RAbstractContainer container, @SuppressWarnings("unused") RNull list, //
                     @Cached("createDimNames()") RemoveFixedAttributeNode remove) {
         RAbstractContainer result = (RAbstractContainer) container.getNonShared();
-        if (isRVectorProfile.profile(container instanceof RVector)) {
-            RVector<?> vector = (RVector<?>) result;
-            if (vector.getInternalDimNames() != null) {
-                vector.setInternalDimNames(null);
-                remove.execute(vector.getAttributes());
-            }
-        } else {
-            result.setDimNames(null);
-        }
+        remove.execute(result);
         return result;
     }
 
@@ -116,9 +104,9 @@ public abstract class UpdateDimNames extends RBuiltinNode {
 
     @Specialization(guards = "list.getLength() > 0")
     protected RAbstractContainer updateDimnames(RAbstractContainer container, RList list, //
-                    @Cached("createDimNames()") SetFixedAttributeNode attrSetter) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
         RAbstractContainer result = (RAbstractContainer) container.getNonShared();
-        setDimNames(result, convertToListOfStrings(list), attrSetter);
+        setDimNamesNode.setDimNames(result, convertToListOfStrings(list));
         return result;
     }
 
@@ -128,58 +116,4 @@ public abstract class UpdateDimNames extends RBuiltinNode {
         throw RError.error(this, RError.Message.DIMNAMES_LIST);
     }
 
-    private void setDimNames(RAbstractContainer container, RList newDimNames, SetFixedAttributeNode attrSetter) {
-        assert newDimNames != null;
-        if (isRVectorProfile.profile(container instanceof RVector)) {
-            RVector<?> vector = (RVector<?>) container;
-            int[] dimensions = vector.getDimensions();
-            if (dimensions == null) {
-                CompilerDirectives.transferToInterpreter();
-                throw RError.error(this, RError.Message.DIMNAMES_NONARRAY);
-            }
-            int newDimNamesLength = newDimNames.getLength();
-            if (newDimNamesLength > dimensions.length) {
-                CompilerDirectives.transferToInterpreter();
-                throw RError.error(this, RError.Message.DIMNAMES_DONT_MATCH_DIMS, newDimNamesLength, dimensions.length);
-            }
-            for (int i = 0; i < newDimNamesLength; i++) {
-                Object dimObject = newDimNames.getDataAt(i);
-                if (dimObject != RNull.instance) {
-                    if (dimObject instanceof String) {
-                        if (dimensions[i] != 1) {
-                            CompilerDirectives.transferToInterpreter();
-                            throw RError.error(this, RError.Message.DIMNAMES_DONT_MATCH_EXTENT, i + 1);
-                        }
-                    } else {
-                        RStringVector dimVector = (RStringVector) dimObject;
-                        if (dimVector == null || dimVector.getLength() == 0) {
-                            newDimNames.updateDataAt(i, RNull.instance, null);
-                        } else if (dimVector.getLength() != dimensions[i]) {
-                            CompilerDirectives.transferToInterpreter();
-                            throw RError.error(this, RError.Message.DIMNAMES_DONT_MATCH_EXTENT, i + 1);
-                        }
-                    }
-                }
-            }
-
-            RList resDimNames = newDimNames;
-            if (newDimNamesLength < dimensions.length) {
-                // resize the array and fill the missing entries with NULL-s
-                resDimNames = (RList) resDimNames.copyResized(dimensions.length, true);
-                resDimNames.setAttributes(newDimNames);
-                for (int i = newDimNamesLength; i < dimensions.length; i++) {
-                    resDimNames.updateDataAt(i, RNull.instance, null);
-                }
-            }
-            if (vector.getAttributes() == null) {
-                vector.initAttributes(RAttributesLayout.createDimNames(resDimNames));
-            } else {
-                attrSetter.execute(vector.getAttributes(), resDimNames);
-            }
-            resDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
-            vector.setInternalDimNames(resDimNames);
-        } else {
-            container.setDimNames(newDimNames);
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
index b9f41698d5966fe4c557badf8f03da94e0b95225..329730c362cfc6ee005247514fa33506811d928e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
@@ -15,7 +15,9 @@ import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -44,10 +46,15 @@ public abstract class UpdateLevels extends RBuiltinNode {
         return v;
     }
 
+    protected SetFixedAttributeNode createSetLevelsAttrNode() {
+        return SetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
+    }
+
     @Specialization(guards = "!isRNull(levels)")
-    protected RAbstractVector updateLevels(RAbstractVector vector, Object levels) {
+    protected RAbstractVector updateLevels(RAbstractVector vector, Object levels,
+                    @Cached("createSetLevelsAttrNode()") SetFixedAttributeNode setLevelsAttrNode) {
         RVector<?> v = (RVector<?>) vector.getNonShared();
-        v.setAttr(RRuntime.LEVELS_ATTR_KEY, levels);
+        setLevelsAttrNode.execute(v, levels);
         return v;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
index f05261a585f42113af69f41576f5a2897eddc6df..02c1ab3e723189351e01281fc7714e35326c9270 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
@@ -29,6 +29,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
@@ -45,6 +46,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 public abstract class UpdateOldClass extends RBuiltinNode {
 
     @Child private CastStringNode castStringNode;
+    @Child private SetClassAttributeNode setClassAttributeNode = SetClassAttributeNode.create();
 
     @Specialization(guards = "!isStringVector(className)")
     protected Object setOldClass(RAbstractContainer arg, RAbstractVector className) {
@@ -73,14 +75,16 @@ public abstract class UpdateOldClass extends RBuiltinNode {
     @TruffleBoundary
     protected Object setOldClass(RAbstractContainer arg, RStringVector className) {
         RAbstractContainer result = (RAbstractContainer) arg.getNonShared();
-        return result.setClassAttr(className);
+        setClassAttributeNode.execute(result, className);
+        return result;
     }
 
     @Specialization
     @TruffleBoundary
     protected Object setOldClass(RAbstractContainer arg, @SuppressWarnings("unused") RNull className) {
         RAbstractContainer result = (RAbstractContainer) arg.getNonShared();
-        return result.setClassAttr(null);
+        setClassAttributeNode.reset(result);
+        return result;
     }
 
     protected boolean isStringVector(RAbstractVector className) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
index a2b8ddcf234c55e836d8af7397a79d7e2ea40423..804b73b66704a390fa5dee5d937b25a7c650b76d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
@@ -20,6 +20,8 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
@@ -35,9 +37,7 @@ import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 
 @RBuiltin(name = "storage.mode<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, behavior = PURE)
@@ -47,11 +47,14 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
     @Child private TypeofNode typeof;
     @Child private CastTypeNode castTypeNode;
     @Child private IsFactorNode isFactor;
+    @Child private SetClassAttributeNode setClassAttrNode;
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
     @Specialization
-    protected Object update(Object x, String value, @Cached("create()") ArrayAttributeNode attrAttrAccess) {
+    protected Object update(Object x, String value,
+                    @Cached("create()") ArrayAttributeNode attrAttrAccess,
+                    @Cached("create()") SetAttributeNode setAttrNode) {
         RType mode = typeFromMode.execute(value);
         if (mode == RType.DefunctReal || mode == RType.DefunctSingle) {
             errorProfile.enter();
@@ -80,13 +83,19 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
                             String attrName = attr.getName();
                             Object v = attr.getValue();
                             if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
+
+                                if (setClassAttrNode == null) {
+                                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                                    setClassAttrNode = insert(SetClassAttributeNode.create());
+                                }
+
                                 if (v == RNull.instance) {
-                                    rresult = (RAbstractContainer) rresult.setClassAttr(null);
+                                    setClassAttrNode.reset(rresult);
                                 } else {
-                                    rresult = (RAbstractContainer) rresult.setClassAttr((RStringVector) v);
+                                    setClassAttrNode.execute(rresult, v);
                                 }
                             } else {
-                                rresult.setAttr(Utils.intern(attrName), v);
+                                setAttrNode.execute(rresult, Utils.intern(attrName), v);
                             }
                         }
                         return rresult;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
index 2fdba2452bbd296c15841f87e7aead60fb576a88..83f99a9513a2e09bb32b33e7d754e008d0e4af4a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java
@@ -32,6 +32,9 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.Lapply.LapplyInternalNode;
@@ -50,7 +53,6 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -80,7 +82,6 @@ public abstract class VApply extends RBuiltinNode {
 
     private final ConditionProfile useNamesProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile dimsProfile = ConditionProfile.createBinaryProfile();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final NACheck naCheck = NACheck.create();
 
     @Child private LapplyInternalNode doApply = LapplyInternalNodeGen.create();
@@ -90,6 +91,9 @@ public abstract class VApply extends RBuiltinNode {
     @Child private CastIntegerNode castInteger;
     @Child private CastLogicalNode castLogical;
     @Child private CastStringNode castString;
+    @Child private SetDimAttributeNode setDimNode;
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
+    @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create();
 
     @Override
     protected void createCasts(CastBuilder casts) {
@@ -186,12 +190,16 @@ public abstract class VApply extends RBuiltinNode {
         }
 
         if (dimsProfile.profile(funValueVecLen > 1)) {
-            result.setDimensions(new int[]{funValueVecLen, applyResult.length});
+            if (setDimNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setDimNode = insert(SetDimAttributeNode.create());
+            }
+            setDimNode.setDimensions(result, new int[]{funValueVecLen, applyResult.length});
         }
 
         // TODO: handle names in case of matrices
         if (useNamesProfile.profile(RRuntime.fromLogical(useNames))) {
-            RStringVector names = vecMat.getNames(attrProfiles);
+            RStringVector names = getNamesNode.getNames(vecMat);
             RStringVector newNames = null;
             if (names != null) {
                 newNames = names;
@@ -199,7 +207,7 @@ public abstract class VApply extends RBuiltinNode {
                 newNames = (RStringVector) vecMat.copy();
             }
             if (newNames != null) {
-                result.setNames(newNames);
+                setNamesNode.setNames(result, newNames);
             }
         }
         return result;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
index ec76dd55c89e32226ef5eafac0317d653103d41b..14614074f986b56a2698b9eccd9b6a13189b4b8d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.WhichFunctionsFactory.WhichMaxNodeGen;
@@ -37,7 +38,6 @@ import com.oracle.truffle.r.nodes.builtin.base.WhichFunctionsFactory.WhichMinNod
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -64,7 +64,7 @@ public class WhichFunctions {
                         @Cached("create()") VectorLengthProfile lengthProfile,
                         @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
                         @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile,
-                        @Cached("create()") RAttributeProfiles attrProfiles,
+                        @Cached("create()") GetNamesAttributeNode getNamesNode,
                         @Cached("create()") NACheck naCheck) {
             int length = lengthProfile.profile(x.getLength());
             loopProfile.profileCounted(length);
@@ -83,7 +83,7 @@ public class WhichFunctions {
                     result[pos++] = i + 1;
                 }
             }
-            RStringVector names = x.getNames(attrProfiles);
+            RStringVector names = getNamesNode.getNames(x);
             if (hasNamesProfile.profile(names != null)) {
                 // collect result names
                 String[] resultNames = new String[resultLength];
@@ -122,7 +122,7 @@ public class WhichFunctions {
                         @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
                         @Cached("createBinaryProfile()") ConditionProfile isNaNProfile,
                         @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile,
-                        @Cached("create()") RAttributeProfiles attrProfiles) {
+                        @Cached("create()") GetNamesAttributeNode getNamesNode) {
             int length = lengthProfile.profile(x.getLength());
             loopProfile.profileCounted(length);
             double extreme = Double.NaN;
@@ -138,7 +138,7 @@ public class WhichFunctions {
             if (isNaNProfile.profile(extremeIndex == -1)) {
                 return RDataFactory.createEmptyIntVector();
             }
-            RStringVector names = x.getNames(attrProfiles);
+            RStringVector names = getNamesNode.getNames(x);
             if (hasNamesProfile.profile(names != null)) {
                 // collect result names
                 RStringVector resultNames = RDataFactory.createStringVectorFromScalar(names.getDataAt(extremeIndex));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
similarity index 68%
rename from com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
rename to com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index 59786926cd8806b63b998768c62575be03c53fb2..279790c9b7f5c15e33802be3b956aefe106a481d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -15,7 +15,6 @@ import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
-import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
@@ -41,24 +40,43 @@ import com.oracle.truffle.r.library.methods.SlotFactory.R_getSlotNodeGen;
 import com.oracle.truffle.r.library.methods.SlotFactory.R_setSlotNodeGen;
 import com.oracle.truffle.r.library.methods.SubstituteDirectNodeGen;
 import com.oracle.truffle.r.library.parallel.ParallelFunctionsFactory.MCIsChildNodeGen;
+import com.oracle.truffle.r.library.stats.Cauchy;
+import com.oracle.truffle.r.library.stats.Cauchy.DCauchy;
+import com.oracle.truffle.r.library.stats.Cauchy.PCauchy;
+import com.oracle.truffle.r.library.stats.Cauchy.RCauchy;
 import com.oracle.truffle.r.library.stats.CdistNodeGen;
+import com.oracle.truffle.r.library.stats.Chisq;
 import com.oracle.truffle.r.library.stats.CompleteCases;
 import com.oracle.truffle.r.library.stats.CovcorNodeGen;
 import com.oracle.truffle.r.library.stats.CutreeNodeGen;
+import com.oracle.truffle.r.library.stats.DBeta;
+import com.oracle.truffle.r.library.stats.DPois;
 import com.oracle.truffle.r.library.stats.Dbinom;
+import com.oracle.truffle.r.library.stats.Df;
 import com.oracle.truffle.r.library.stats.DoubleCentreNodeGen;
+import com.oracle.truffle.r.library.stats.Dt;
+import com.oracle.truffle.r.library.stats.Exp.DExp;
+import com.oracle.truffle.r.library.stats.Exp.PExp;
+import com.oracle.truffle.r.library.stats.Exp.QExp;
+import com.oracle.truffle.r.library.stats.Exp.RExp;
+import com.oracle.truffle.r.library.stats.GammaFunctions.DGamma;
 import com.oracle.truffle.r.library.stats.GammaFunctions.QgammaFunc;
+import com.oracle.truffle.r.library.stats.Geom;
+import com.oracle.truffle.r.library.stats.Geom.DGeom;
+import com.oracle.truffle.r.library.stats.Geom.RGeom;
+import com.oracle.truffle.r.library.stats.LogNormal;
+import com.oracle.truffle.r.library.stats.LogNormal.DLNorm;
+import com.oracle.truffle.r.library.stats.LogNormal.PLNorm;
+import com.oracle.truffle.r.library.stats.LogNormal.QLNorm;
+import com.oracle.truffle.r.library.stats.Pbeta;
 import com.oracle.truffle.r.library.stats.Pbinom;
 import com.oracle.truffle.r.library.stats.Pf;
 import com.oracle.truffle.r.library.stats.Pnorm;
 import com.oracle.truffle.r.library.stats.Qbinom;
 import com.oracle.truffle.r.library.stats.Qnorm;
 import com.oracle.truffle.r.library.stats.RBeta;
-import com.oracle.truffle.r.library.stats.RCauchy;
 import com.oracle.truffle.r.library.stats.RChisq;
-import com.oracle.truffle.r.library.stats.RExp;
 import com.oracle.truffle.r.library.stats.RGamma;
-import com.oracle.truffle.r.library.stats.RGeom;
 import com.oracle.truffle.r.library.stats.RHyper;
 import com.oracle.truffle.r.library.stats.RLogis;
 import com.oracle.truffle.r.library.stats.RMultinomNodeGen;
@@ -66,6 +84,7 @@ import com.oracle.truffle.r.library.stats.RNbinomMu;
 import com.oracle.truffle.r.library.stats.RNchisq;
 import com.oracle.truffle.r.library.stats.RPois;
 import com.oracle.truffle.r.library.stats.RWeibull;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions;
 import com.oracle.truffle.r.library.stats.RandGenerationFunctionsFactory;
 import com.oracle.truffle.r.library.stats.Rbinom;
 import com.oracle.truffle.r.library.stats.Rf;
@@ -76,7 +95,6 @@ import com.oracle.truffle.r.library.stats.Signrank.RSignrank;
 import com.oracle.truffle.r.library.stats.SplineFunctionsFactory.SplineCoefNodeGen;
 import com.oracle.truffle.r.library.stats.SplineFunctionsFactory.SplineEvalNodeGen;
 import com.oracle.truffle.r.library.stats.StatsFunctionsFactory;
-import com.oracle.truffle.r.library.stats.StatsUtil;
 import com.oracle.truffle.r.library.stats.Wilcox.RWilcox;
 import com.oracle.truffle.r.library.tools.C_ParseRdNodeGen;
 import com.oracle.truffle.r.library.tools.DirChmodNodeGen;
@@ -91,7 +109,6 @@ import com.oracle.truffle.r.library.utils.ObjectSizeNodeGen;
 import com.oracle.truffle.r.library.utils.RprofNodeGen;
 import com.oracle.truffle.r.library.utils.RprofmemNodeGen;
 import com.oracle.truffle.r.library.utils.TypeConvertNodeGen;
-import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode;
 import com.oracle.truffle.r.nodes.objects.GetPrimNameNodeGen;
@@ -99,8 +116,6 @@ import com.oracle.truffle.r.nodes.objects.NewObjectNodeGen;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalCode;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -108,21 +123,21 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
- * {@code .Call} {@code .Fortran}, {@code .External}, {@code .External2}, {@code External.graphics}
- * functions.
+ * {@code .Call}, {@code .Call.graphics}, {@code .External}, {@code .External2},
+ * {@code External.graphics} functions, which share a common signature.
  *
  * TODO Completeness (more types, more error checks), Performance (copying). Especially all the
  * subtleties around copying.
  *
  * See <a href="https://stat.ethz.ch/R-manual/R-devel/library/base/html/Foreign.html">here</a>.
  */
-public class ForeignFunctions {
+public class CallAndExternalFunctions {
 
     @TruffleBoundary
     protected static Object encodeArgumentPairList(RArgsValuesAndNames args, String symbolName) {
@@ -135,158 +150,28 @@ public class ForeignFunctions {
         return list;
     }
 
-    /**
-     * Locator for "builtin" package function implementations. The "builtin" packages contain many
-     * functions that are called from R code via the FFI, e.g. {@code .Call}, but implemented
-     * internally in GnuR, and not necessarily following the FFI API. The value passed to
-     * {@code .Call} etc., is a symbol, created when the package is loaded and stored in the
-     * namespace environment of the package, that is a list-valued object. Evidently these
-     * "builtins" are somewhat similar to the {@code .Primitive} and {@code .Internal} builtins and,
-     * similarly, most of these are re-implemented in Java in FastR. The
-     * {@link #lookupBuiltin(RList)} method checks the name in the list object and returns the
-     * {@link RExternalBuiltinNode} that implements the function, or {@code null}. A {@code null}
-     * result implies that the builtin is not implemented in Java, but called directly via the FFI
-     * interface, which is only possible for functions that use the FFI in a way that FastR can
-     * handle.
-     */
-    protected abstract static class LookupAdapter extends RBuiltinNode {
-        protected static class UnimplementedExternal extends RExternalBuiltinNode {
-            private final String name;
-
-            public UnimplementedExternal(String name) {
-                this.name = name;
-            }
-
-            @Override
-            public final Object call(RArgsValuesAndNames args) {
-                throw RInternalError.unimplemented("unimplemented external builtin: " + name);
-            }
-        }
-
-        protected abstract RExternalBuiltinNode lookupBuiltin(RList f);
-
-        private static final String UNKNOWN_EXTERNAL_BUILTIN = "UNKNOWN_EXTERNAL_BUILTIN";
-
-        protected static String lookupName(RList f) {
-            CompilerAsserts.neverPartOfCompilation();
-            if (f.getNames() != null) {
-                RAbstractStringVector names = f.getNames();
-                for (int i = 0; i < names.getLength(); i++) {
-                    if (names.getDataAt(i).equals("name")) {
-                        String name = RRuntime.asString(f.getDataAt(i));
-                        return name != null ? name : UNKNOWN_EXTERNAL_BUILTIN;
-                    }
-                }
-            }
-            return UNKNOWN_EXTERNAL_BUILTIN;
-        }
-
-        @TruffleBoundary
-        protected RuntimeException fallback(Object fobj) {
-            String name = null;
-            if (fobj instanceof RList) {
-                name = lookupName((RList) fobj);
-                name = name == UNKNOWN_EXTERNAL_BUILTIN ? null : name;
-                if (name != null && lookupBuiltin((RList) fobj) != null) {
-                    /*
-                     * if we reach this point, then the cache saw a different value for f. the lists
-                     * that contain the information about native calls are never expected to change.
-                     */
-                    throw RInternalError.shouldNotReachHere("fallback reached for " + getRBuiltin().name() + " " + name);
-                }
-            }
-            throw RError.nyi(this, getRBuiltin().name() + " specialization failure: " + (name == null ? "<unknown>" : name));
-        }
-
-        @Child private ExtractNativeCallInfoNode extractSymbolInfoNode = ExtractNativeCallInfoNodeGen.create();
-
-        protected NativeCallInfo extractSymbolInfo(VirtualFrame frame, RList symbol) {
-            return (NativeCallInfo) extractSymbolInfoNode.execute(frame, symbol);
-        }
-
-        protected String checkPackageArg(Object rPackage, BranchProfile errorProfile) {
-            String libName = null;
-            if (!(rPackage instanceof RMissing)) {
-                libName = RRuntime.asString(rPackage);
-                if (libName == null) {
-                    errorProfile.enter();
-                    throw RError.error(this, RError.Message.ARGUMENT_MUST_BE_STRING, "PACKAGE");
-                }
-            }
-            return libName;
-        }
-
-        protected static RExternalBuiltinNode getExternalModelBuiltinNode(String name) {
-            return new RInternalCodeBuiltinNode(RContext.getInstance(), "stats", RInternalCode.loadSourceRelativeTo(StatsUtil.class, "model.R"), name);
-        }
-    }
-
-    /**
-     * Interface to .Fortran native functions. Some functions have explicit implementations in
-     * FastR, otherwise the .Fortran interface uses the machinery that implements the .C interface.
-     */
-    @RBuiltin(name = ".Fortran", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
-    public abstract static class Fortran extends LookupAdapter {
-
-        @Override
-        public Object[] getDefaultParameterValues() {
-            return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE, RMissing.instance, RMissing.instance};
-        }
-
-        @Override
-        @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList f) {
-            switch (lookupName(f)) {
-                case "dqrdc2":
-                    return new Dqrdc2();
-                case "dqrcf":
-                    return new Dqrcf();
-                default:
-                    return null;
-            }
-        }
-
-        @SuppressWarnings("unused")
-        @Specialization(limit = "1", guards = {"cached == f", "builtin != null"})
-        protected Object doExternal(VirtualFrame frame, RList f, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding, //
-                        @Cached("f") RList cached, //
-                        @Cached("lookupBuiltin(f)") RExternalBuiltinNode builtin) {
-            return builtin.call(frame, args);
-        }
-
-        @Specialization(guards = "lookupBuiltin(symbol) == null")
-        protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, @SuppressWarnings("unused") Object rPackage,
-                        @SuppressWarnings("unused") RMissing encoding) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
-            return DotC.dispatch(this, nativeCallInfo, naok, dup, args);
-        }
-
-        @Specialization
-        protected RList c(RAbstractStringVector f, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, @SuppressWarnings("unused") RMissing encoding, //
-                        @Cached("create()") BranchProfile errorProfile) {
-            String libName = checkPackageArg(rPackage, errorProfile);
-            DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Fortran, null, null);
-            DLL.SymbolHandle func = DLL.findSymbol(f.getDataAt(0), libName, rns);
-            if (func == DLL.SYMBOL_NOT_FOUND) {
-                errorProfile.enter();
-                throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, f);
-            }
-            return DotC.dispatch(this, new NativeCallInfo(f.getDataAt(0), func, rns.getDllInfo()), naok, dup, args);
-        }
-
-        @SuppressWarnings("unused")
-        @Fallback
-        protected Object fallback(Object f, Object args, Object naok, Object dup, Object rPackage, Object encoding) {
-            throw fallback(f);
-        }
+    protected abstract static class CallRFFIAdapter extends LookupAdapter {
+        @Child protected CallRFFI.CallRFFINode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode();
     }
 
     /**
      * Handles the generic case, but also many special case functions that are called from the
      * default packages.
+     *
+     * The native function to be called can be specified in two ways:
+     * <ol>
+     * <li>as an object of R class {@code NativeSymbolInfo} (passed as an {@link RList}. In this
+     * case {@code .PACKAGE} is ignored even if provided.</li>
+     * <li>as a character string. If {@code .PACKAGE} is provided the search is restricted to that
+     * package, else the symbol is searched in all loaded packages (evidently dangerous as the
+     * symbol could be duplicated)</li>
+     * </ol>
+     * Many of the functions in the builtin packages have been translated to Java which is handled
+     * by specializations that {@link #lookupBuiltin(RList)}. N.N. In principle such a function
+     * could be invoked by a string but experimentally that situation has never been encountered.
      */
     @RBuiltin(name = ".Call", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotCall extends LookupAdapter {
+    public abstract static class DotCall extends CallRFFIAdapter {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
@@ -297,8 +182,8 @@ public class ForeignFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList f) {
-            String name = lookupName(f);
+        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
+            String name = lookupName(symbol);
             switch (name) {
                 // methods
                 case "R_initMethodDispatch":
@@ -409,8 +294,48 @@ public class ForeignFunctions {
                     return RandGenerationFunctionsFactory.Function2_IntNodeGen.create(new Rbinom());
                 case "pbinom":
                     return StatsFunctionsFactory.Function3_2NodeGen.create(new Pbinom());
+                case "pbeta":
+                    return StatsFunctionsFactory.Function3_2NodeGen.create(new Pbeta());
+                case "dcauchy":
+                    return StatsFunctionsFactory.Function3_1NodeGen.create(new DCauchy());
+                case "pcauchy":
+                    return StatsFunctionsFactory.Function3_2NodeGen.create(new PCauchy());
+                case "qcauchy":
+                    return StatsFunctionsFactory.Function3_2NodeGen.create(new Cauchy.QCauchy());
                 case "pf":
                     return StatsFunctionsFactory.Function3_2NodeGen.create(new Pf());
+                case "df":
+                    return StatsFunctionsFactory.Function3_1NodeGen.create(new Df());
+                case "dgamma":
+                    return StatsFunctionsFactory.Function3_1NodeGen.create(new DGamma());
+                case "dchisq":
+                    return StatsFunctionsFactory.Function2_1NodeGen.create(new Chisq.DChisq());
+                case "qgeom":
+                    return StatsFunctionsFactory.Function2_2NodeGen.create(new Geom.QGeom());
+                case "pchisq":
+                    return StatsFunctionsFactory.Function2_2NodeGen.create(new Chisq.PChisq());
+                case "dexp":
+                    return StatsFunctionsFactory.Function2_1NodeGen.create(new DExp());
+                case "pexp":
+                    return StatsFunctionsFactory.Function2_2NodeGen.create(new PExp());
+                case "qexp":
+                    return StatsFunctionsFactory.Function2_2NodeGen.create(new QExp());
+                case "dgeom":
+                    return StatsFunctionsFactory.Function2_1NodeGen.create(new DGeom());
+                case "dpois":
+                    return StatsFunctionsFactory.Function2_1NodeGen.create(new DPois());
+                case "dbeta":
+                    return StatsFunctionsFactory.Function3_1NodeGen.create(new DBeta());
+                case "dt":
+                    return StatsFunctionsFactory.Function2_1NodeGen.create(new Dt());
+                case "rlnorm":
+                    return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new LogNormal.RLNorm());
+                case "dlnorm":
+                    return StatsFunctionsFactory.Function3_1NodeGen.create(new DLNorm());
+                case "qlnorm":
+                    return StatsFunctionsFactory.Function3_2NodeGen.create(new QLNorm());
+                case "plnorm":
+                    return StatsFunctionsFactory.Function3_2NodeGen.create(new PLNorm());
                 case "rmultinom":
                     return RMultinomNodeGen.create();
                 case "Approx":
@@ -501,7 +426,7 @@ public class ForeignFunctions {
                     return getExternalModelBuiltinNode("updateform");
 
                 case "Cdqrls":
-                    return new RInternalCodeBuiltinNode(RContext.getInstance(), "stats", RInternalCode.loadSourceRelativeTo(StatsUtil.class, "lm.R"), "Cdqrls");
+                    return new RInternalCodeBuiltinNode(RContext.getInstance(), "stats", RInternalCode.loadSourceRelativeTo(RandGenerationFunctions.class, "lm.R"), "Cdqrls");
 
                 case "dnorm":
                     return StatsFunctionsFactory.Function3_1NodeGen.create(new Dnorm4());
@@ -568,44 +493,67 @@ public class ForeignFunctions {
             }
         }
 
+        /**
+         * {@code .NAME = NativeSymbolInfo} implemented as a builtin.
+         */
         @SuppressWarnings("unused")
-        @Specialization(limit = "1", guards = {"cached == f", "builtin != null"})
-        protected Object doExternal(VirtualFrame frame, RList f, RArgsValuesAndNames args, RMissing packageName, //
-                        @Cached("f") RList cached, //
-                        @Cached("lookupBuiltin(f)") RExternalBuiltinNode builtin) {
+        @Specialization(limit = "1", guards = {"cached == symbol", "builtin != null"})
+        protected Object doExternal(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, //
+                        @Cached("symbol") RList cached, //
+                        @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin) {
             return builtin.call(frame, args);
         }
 
-        @Specialization
-        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, args.getArguments());
+        /**
+         * {@code .NAME = NativeSymbolInfo} implementation remains in native code (e.g. non-builtin
+         * package)
+         */
+        @SuppressWarnings("unused")
+        @Specialization(limit = "1", guards = {"cached == symbol"})
+        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, //
+                        @Cached("symbol") RList cached, //
+                        @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
+            return callRFFINode.invokeCall(nativeCallInfo, args.getArguments());
         }
 
+        /**
+         * {@code .NAME = string}, no package specified.
+         */
         @Specialization
-        protected Object callNamedFunction(String name, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
-            return callNamedFunctionWithPackage(name, args, null);
+        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName, //
+                        @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns) {
+            return callNamedFunctionWithPackage(symbol, args, null, rns);
         }
 
+        /**
+         * {@code .NAME = string, .PACKAGE = package}. An error if package provided and it does not
+         * define that symbol.
+         */
         @Specialization
-        protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
-            DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Call, null, null);
-            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
+        protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName, //
+                        @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns) {
+            DLL.SymbolHandle func = DLL.findSymbol(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
-                throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
+                throw RError.error(this, RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "Call", packageName);
             }
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), args.getArguments());
+            return callRFFINode.invokeCall(new NativeCallInfo(symbol, func, rns.getDllInfo()), args.getArguments());
         }
 
+        @SuppressWarnings("unused")
         @Fallback
-        protected Object dotCallFallback(Object fobj, @SuppressWarnings("unused") Object args, @SuppressWarnings("unused") Object packageName) {
-            throw fallback(fobj);
+        protected Object dotCallFallback(Object symbol, Object args, Object packageName) {
+            throw fallback(symbol);
         }
+
     }
 
+    /**
+     * The interpretation of the {@code .NAME} and {code .PACKAGE} arguments as are for
+     * {@link DotCall}.
+     */
     @RBuiltin(name = ".External", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotExternal extends LookupAdapter {
+    public abstract static class DotExternal extends CallRFFIAdapter {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
@@ -655,35 +603,38 @@ public class ForeignFunctions {
         }
 
         @SuppressWarnings("unused")
-        @Specialization(limit = "1", guards = {"cached == f", "builtin != null"})
-        protected Object doExternal(VirtualFrame frame, RList f, RArgsValuesAndNames args, RMissing packageName, //
-                        @Cached("f") RList cached, //
-                        @Cached("lookupBuiltin(f)") RExternalBuiltinNode builtin) {
+        @Specialization(limit = "1", guards = {"cached == symbol", "builtin != null"})
+        protected Object doExternal(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, //
+                        @Cached("symbol") RList cached, //
+                        @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin) {
             return builtin.call(frame, args);
         }
 
-        @Specialization
-        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+        @SuppressWarnings("unused")
+        @Specialization(limit = "1", guards = {"cached == symbol"})
+        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, //
+                        @Cached("symbol") RList cached, //
+                        @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, new Object[]{list});
+            return callRFFINode.invokeCall(nativeCallInfo, new Object[]{list});
         }
 
         @Specialization
-        protected Object callNamedFunction(String name, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
-            return callNamedFunctionWithPackage(name, args, null);
+        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName, // )
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
+            return callNamedFunctionWithPackage(symbol, args, null, rns);
         }
 
         @Specialization
-        protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
-            DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.External, null, null);
-            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
+        protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName, //
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
+            DLL.SymbolHandle func = DLL.findSymbol(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
-                throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
+                throw RError.error(this, RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "External", packageName);
             }
-            Object list = encodeArgumentPairList(args, name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{list});
+            Object list = encodeArgumentPairList(args, symbol);
+            return callRFFINode.invokeCall(new NativeCallInfo(symbol, func, rns.getDllInfo()), new Object[]{list});
         }
 
         @Fallback
@@ -693,7 +644,7 @@ public class ForeignFunctions {
     }
 
     @RBuiltin(name = ".External2", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotExternal2 extends LookupAdapter {
+    public abstract static class DotExternal2 extends CallRFFIAdapter {
         private static final Object CALL = "call";
         private static final Object OP = "op";
         private static final Object RHO = "rho";
@@ -702,14 +653,14 @@ public class ForeignFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList f) {
+        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
             if (FastROptions.UseInternalGraphics.getBooleanValue()) {
-                switch (lookupName(f)) {
+                switch (lookupName(symbol)) {
                     case "C_par":
                         return new C_Par();
                 }
             }
-            String name = lookupName(f);
+            String name = lookupName(symbol);
             switch (name) {
                 // tools
                 case "writetable":
@@ -727,37 +678,40 @@ public class ForeignFunctions {
         }
 
         @SuppressWarnings("unused")
-        @Specialization(limit = "1", guards = {"cached == f", "builtin != null"})
-        protected Object doExternal(VirtualFrame frame, RList f, RArgsValuesAndNames args, RMissing packageName, //
-                        @Cached("f") RList cached, //
-                        @Cached("lookupBuiltin(f)") RExternalBuiltinNode builtin) {
+        @Specialization(limit = "1", guards = {"cached == symbol", "builtin != null"})
+        protected Object doExternal(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, //
+                        @Cached("symbol") RList cached, //
+                        @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin) {
             return builtin.call(frame, args);
         }
 
-        @Specialization
-        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+        @SuppressWarnings("unused")
+        @Specialization(limit = "1", guards = {"cached == symbol"})
+        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, //
+                        @Cached("symbol") RList cached, //
+                        @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
             // TODO: provide proper values for the CALL, OP and RHO parameters
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, new Object[]{CALL, OP, list, RHO});
+            return callRFFINode.invokeCall(nativeCallInfo, new Object[]{CALL, OP, list, RHO});
         }
 
         @Specialization
-        protected Object callNamedFunction(String name, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
-            return callNamedFunctionWithPackage(name, args, null);
+        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName, // )
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
+            return callNamedFunctionWithPackage(symbol, args, null, rns);
         }
 
         @Specialization
-        protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
-            DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.External, null, null);
-            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
+        protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName, //
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
+            DLL.SymbolHandle func = DLL.findSymbol(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
-                throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
+                throw RError.error(this, RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "External2", packageName);
             }
-            Object list = encodeArgumentPairList(args, name);
+            Object list = encodeArgumentPairList(args, symbol);
             // TODO: provide proper values for the CALL, OP and RHO parameters
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{CALL, OP, list, RHO});
+            return callRFFINode.invokeCall(new NativeCallInfo(symbol, func, rns.getDllInfo()), new Object[]{CALL, OP, list, RHO});
         }
 
         @Fallback
@@ -767,7 +721,7 @@ public class ForeignFunctions {
     }
 
     @RBuiltin(name = ".External.graphics", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotExternalGraphics extends LookupAdapter {
+    public abstract static class DotExternalGraphics extends CallRFFIAdapter {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
@@ -797,7 +751,7 @@ public class ForeignFunctions {
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
             NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, new Object[]{list});
+            return callRFFINode.invokeCall(nativeCallInfo, new Object[]{list});
         }
 
         @Specialization
@@ -814,7 +768,7 @@ public class ForeignFunctions {
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
             Object list = encodeArgumentPairList(args, name);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{list});
+            return callRFFINode.invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{list});
         }
 
         @Fallback
@@ -824,7 +778,7 @@ public class ForeignFunctions {
     }
 
     @RBuiltin(name = ".Call.graphics", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotCallGraphics extends LookupAdapter {
+    public abstract static class DotCallGraphics extends CallRFFIAdapter {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
@@ -853,7 +807,7 @@ public class ForeignFunctions {
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
             NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(nativeCallInfo, args.getArguments());
+            return callRFFINode.invokeCall(nativeCallInfo, args.getArguments());
         }
 
         @Specialization
@@ -870,7 +824,7 @@ public class ForeignFunctions {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), args.getArguments());
+            return callRFFINode.invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), args.getArguments());
         }
 
         @Fallback
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java
deleted file mode 100644
index 8009ea798359a524bc8b59bd25bdd0408fbe1d0e..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (c) 1995-2012, The R Core Team
- * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-package com.oracle.truffle.r.nodes.builtin.base.foreign;
-
-import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
-import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
-
-import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.runtime.ArgumentsSignature;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RMissing;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
-import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
-
-/**
- * {@code .C} functions.
- *
- * TODO Completeness (more types, more error checks), Performance (copying). Especially all the
- * subtleties around copying.
- *
- * See <a href="https://stat.ethz.ch/R-manual/R-devel/library/base/html/Foreign.html">here</a>.
- */
-@RBuiltin(name = ".C", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
-public abstract class DotC extends RBuiltinNode {
-
-    private static final int SCALAR_DOUBLE = 0;
-    private static final int SCALAR_INT = 1;
-    private static final int SCALAR_LOGICAL = 2;
-    @SuppressWarnings("unused") private static final int SCALAR_STRING = 3;
-    private static final int VECTOR_DOUBLE = 10;
-    private static final int VECTOR_INT = 11;
-    private static final int VECTOR_LOGICAL = 12;
-    @SuppressWarnings("unused") private static final int VECTOR_STRING = 12;
-
-    @Child private ExtractNativeCallInfoNode extractSymbolInfoNode = ExtractNativeCallInfoNodeGen.create();
-
-    protected NativeCallInfo extractSymbolInfo(VirtualFrame frame, RList symbol) {
-        return (NativeCallInfo) extractSymbolInfoNode.execute(frame, symbol);
-    }
-
-    @Override
-    public Object[] getDefaultParameterValues() {
-        return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE, RMissing.instance, RMissing.instance};
-    }
-
-    @SuppressWarnings("unused")
-    @Specialization
-    protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding) {
-        NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
-        return dispatch(this, nativeCallInfo, naok, dup, args);
-    }
-
-    @SuppressWarnings("unused")
-    @Specialization
-    protected RList c(RAbstractStringVector f, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding, //
-                    @Cached("create()") BranchProfile errorProfile) {
-        String libName = null;
-        if (!(rPackage instanceof RMissing)) {
-            libName = RRuntime.asString(rPackage);
-            if (libName == null) {
-                errorProfile.enter();
-                throw RError.error(this, RError.Message.ARGUMENT_MUST_BE_STRING, "PACKAGE");
-            }
-        }
-        DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.C, null, null);
-        DLL.SymbolHandle func = DLL.findSymbol(f.getDataAt(0), libName, rns);
-        if (func == DLL.SYMBOL_NOT_FOUND) {
-            errorProfile.enter();
-            throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, f);
-        }
-        return dispatch(this, new NativeCallInfo(f.getDataAt(0), func, rns.getDllInfo()), naok, dup, args);
-    }
-
-    private static int[] checkNAs(RBuiltinNode node, int argIndex, int[] data) {
-        CompilerAsserts.neverPartOfCompilation();
-        for (int i = 0; i < data.length; i++) {
-            if (RRuntime.isNA(data[i])) {
-                throw RError.error(node, RError.Message.NA_IN_FOREIGN_FUNCTION_CALL, argIndex);
-            }
-        }
-        return data;
-    }
-
-    private static double[] checkNAs(RBuiltinNode node, int argIndex, double[] data) {
-        CompilerAsserts.neverPartOfCompilation();
-        for (int i = 0; i < data.length; i++) {
-            if (!RRuntime.isFinite(data[i])) {
-                throw RError.error(node, RError.Message.NA_NAN_INF_IN_FOREIGN_FUNCTION_CALL, argIndex);
-            }
-        }
-        return data;
-    }
-
-    private static RStringVector validateArgNames(int argsLength, ArgumentsSignature signature) {
-        String[] listArgNames = new String[argsLength];
-        for (int i = 0; i < argsLength; i++) {
-            String name = signature.getName(i);
-            if (name == null) {
-                name = RRuntime.NAMES_ATTR_EMPTY_VALUE;
-            }
-            listArgNames[i] = name;
-        }
-        return RDataFactory.createStringVector(listArgNames, RDataFactory.COMPLETE_VECTOR);
-    }
-
-    @TruffleBoundary
-    protected static RList dispatch(RBuiltinNode node, NativeCallInfo nativeCallInfo, byte naok, byte dup, RArgsValuesAndNames args) {
-        @SuppressWarnings("unused")
-        boolean dupArgs = RRuntime.fromLogical(dup);
-        @SuppressWarnings("unused")
-        boolean checkNA = RRuntime.fromLogical(naok);
-        // Analyze the args, making copies (ignoring dup for now)
-        Object[] array = args.getArguments();
-        int[] argTypes = new int[array.length];
-        Object[] nativeArgs = new Object[array.length];
-        for (int i = 0; i < array.length; i++) {
-            Object arg = array[i];
-            if (arg instanceof RAbstractDoubleVector) {
-                argTypes[i] = VECTOR_DOUBLE;
-                nativeArgs[i] = checkNAs(node, i + 1, ((RAbstractDoubleVector) arg).materialize().getDataCopy());
-            } else if (arg instanceof RAbstractIntVector) {
-                argTypes[i] = VECTOR_INT;
-                nativeArgs[i] = checkNAs(node, i + 1, ((RAbstractIntVector) arg).materialize().getDataCopy());
-            } else if (arg instanceof RAbstractLogicalVector) {
-                argTypes[i] = VECTOR_LOGICAL;
-                // passed as int[]
-                byte[] data = ((RAbstractLogicalVector) arg).materialize().getDataWithoutCopying();
-                int[] dataAsInt = new int[data.length];
-                for (int j = 0; j < data.length; j++) {
-                    // An NA is an error but the error handling happens in checkNAs
-                    dataAsInt[j] = RRuntime.isNA(data[j]) ? RRuntime.INT_NA : data[j];
-                }
-                nativeArgs[i] = checkNAs(node, i + 1, dataAsInt);
-            } else if (arg instanceof Double) {
-                argTypes[i] = SCALAR_DOUBLE;
-                nativeArgs[i] = checkNAs(node, i + 1, new double[]{(double) arg});
-            } else if (arg instanceof Integer) {
-                argTypes[i] = SCALAR_INT;
-                nativeArgs[i] = checkNAs(node, i + 1, new int[]{(int) arg});
-            } else if (arg instanceof Byte) {
-                argTypes[i] = SCALAR_LOGICAL;
-                nativeArgs[i] = checkNAs(node, i + 1, new int[]{RRuntime.isNA((byte) arg) ? RRuntime.INT_NA : (byte) arg});
-            } else {
-                throw RError.error(node, RError.Message.UNIMPLEMENTED_ARG_TYPE, i + 1);
-            }
-        }
-        RFFIFactory.getRFFI().getCRFFI().invoke(nativeCallInfo, nativeArgs);
-        // we have to assume that the native method updated everything
-        RStringVector listNames = validateArgNames(array.length, args.getSignature());
-        Object[] results = new Object[array.length];
-        for (int i = 0; i < array.length; i++) {
-            switch (argTypes[i]) {
-                case SCALAR_DOUBLE:
-                    results[i] = RDataFactory.createDoubleVector((double[]) nativeArgs[i], RDataFactory.COMPLETE_VECTOR);
-                    break;
-                case SCALAR_INT:
-                    results[i] = RDataFactory.createIntVector((int[]) nativeArgs[i], RDataFactory.COMPLETE_VECTOR);
-                    break;
-                case SCALAR_LOGICAL:
-                    // have to convert back from int[]
-                    int[] nativeIntArgs = (int[]) nativeArgs[i];
-                    byte[] nativeByteArgs = new byte[nativeIntArgs.length];
-                    for (int j = 0; j < nativeByteArgs.length; j++) {
-                        int nativeInt = nativeIntArgs[j];
-                        nativeByteArgs[j] = (byte) (nativeInt == RRuntime.INT_NA ? RRuntime.LOGICAL_NA : nativeInt & 0xFF);
-                    }
-                    results[i] = RDataFactory.createLogicalVector(nativeByteArgs, RDataFactory.COMPLETE_VECTOR);
-                    break;
-                case VECTOR_DOUBLE:
-                    results[i] = ((RAbstractDoubleVector) array[i]).materialize().copyResetData((double[]) nativeArgs[i]);
-                    break;
-                case VECTOR_INT:
-                    results[i] = ((RAbstractIntVector) array[i]).materialize().copyResetData((int[]) nativeArgs[i]);
-                    break;
-                case VECTOR_LOGICAL: {
-                    int[] intData = (int[]) nativeArgs[i];
-                    byte[] byteData = new byte[intData.length];
-                    for (int j = 0; j < intData.length; j++) {
-                        byteData[j] = RRuntime.isNA(intData[j]) ? RRuntime.LOGICAL_NA : RRuntime.asLogical(intData[j] != 0);
-                    }
-                    results[i] = ((RAbstractLogicalVector) array[i]).materialize().copyResetData(byteData);
-                    break;
-                }
-            }
-        }
-        return RDataFactory.createList(results, listNames);
-    }
-
-}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java
index b8dfa18b98a9656c6d2df0059a5589ebf7deda57..3ca0f0c97d0173a30490c3c5cdd8b0bf225426ec 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java
@@ -21,9 +21,11 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.ffi.RApplRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public final class Dqrcf extends RExternalBuiltinNode {
+    @Child private RApplRFFI.RApplRFFINode rApplRFFINode = RFFIFactory.getRFFI().getRApplRFFI().createRApplRFFINode();
 
     private static final String E = RRuntime.NAMES_ATTR_EMPTY_VALUE;
     private static final RStringVector DQRCF_NAMES = RDataFactory.createStringVector(new String[]{E, E, E, E, E, E, "coef", "info"}, RDataFactory.COMPLETE_VECTOR);
@@ -45,9 +47,9 @@ public final class Dqrcf extends RExternalBuiltinNode {
             double[] y = yVec.materialize().getDataTemp();
             double[] b = bVec.materialize().getDataTemp();
             int[] info = infoVec.materialize().getDataTemp();
-            RFFIFactory.getRFFI().getRApplRFFI().dqrcf(x, n, k.getDataAt(0), qraux, y, ny, b, info);
+            rApplRFFINode.dqrcf(x, n, k.getDataAt(0), qraux, y, ny, b, info);
             RDoubleVector coef = RDataFactory.createDoubleVector(b, RDataFactory.COMPLETE_VECTOR);
-            coef.copyAttributesFrom(attrProfiles, bVec);
+            coef.copyAttributesFrom(bVec);
             // @formatter:off
             Object[] data = new Object[]{
                         RDataFactory.createDoubleVector(x, RDataFactory.COMPLETE_VECTOR),
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java
index fb842d465d81c176cdc1f5aeadaab8f3d07326c0..e63b42dd1195018bf6b83324ff0ca72ef2dcdfb1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java
@@ -11,6 +11,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base.foreign;
 
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -20,13 +21,17 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.ffi.RApplRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public final class Dqrdc2 extends RExternalBuiltinNode {
+    @Child private RApplRFFI.RApplRFFINode rApplRFFINode = RFFIFactory.getRFFI().getRApplRFFI().createRApplRFFINode();
 
     private static final String E = RRuntime.NAMES_ATTR_EMPTY_VALUE;
     private static final RStringVector DQRDC2_NAMES = RDataFactory.createStringVector(new String[]{"qr", E, E, E, E, "rank", "qraux", "pivot", E}, RDataFactory.COMPLETE_VECTOR);
 
+    @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create();
+
     @Override
     public RList call(RArgsValuesAndNames args) {
         Object[] argValues = args.getArguments();
@@ -44,10 +49,10 @@ public final class Dqrdc2 extends RExternalBuiltinNode {
             int[] rank = rankVec.materialize().getDataTemp();
             double[] qraux = qrauxVec.materialize().getDataTemp();
             int[] pivot = pivotVec.materialize().getDataTemp();
-            RFFIFactory.getRFFI().getRApplRFFI().dqrdc2(x, ldx, n, p, tol, rank, qraux, pivot, workVec.materialize().getDataCopy());
+            rApplRFFINode.dqrdc2(x, ldx, n, p, tol, rank, qraux, pivot, workVec.materialize().getDataCopy());
             // @formatter:off
             Object[] data = new Object[]{
-                        RDataFactory.createDoubleVector(x, RDataFactory.COMPLETE_VECTOR, xVec.getDimensions()),
+                        RDataFactory.createDoubleVector(x, RDataFactory.COMPLETE_VECTOR, getDimNode.getDimensions(xVec)),
                         argValues[1], argValues[2], argValues[3], argValues[4],
                         RDataFactory.createIntVector(rank, RDataFactory.COMPLETE_VECTOR),
                         RDataFactory.createDoubleVector(qraux, RDataFactory.COMPLETE_VECTOR),
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ExtractNativeCallInfoNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ExtractNativeCallInfoNode.java
deleted file mode 100644
index 47d1f4a19c04070de6ce485cc2b780ee8f2bca86..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ExtractNativeCallInfoNode.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.builtin.base.foreign;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
-import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RExternalPtr;
-import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RLogical;
-import com.oracle.truffle.r.runtime.data.RMissing;
-import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
-import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
-import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-
-/**
- * Extracts the salient information needed for a native call from the {@link RList} value provided
- * from R.
- */
-public abstract class ExtractNativeCallInfoNode extends Node {
-    @Child private ExtractVectorNode nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-    @Child private ExtractVectorNode addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-    @Child private ExtractVectorNode packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-    @Child private ExtractVectorNode infoExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-
-    protected abstract Object execute(VirtualFrame frame, RList symbol);
-
-    @Specialization
-    protected Object extractNativeCallInfo(VirtualFrame frame, RList symbol) {
-        if (nameExtract == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-        }
-        if (addressExtract == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-        }
-        if (packageExtract == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
-        }
-        String name = RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
-        SymbolHandle address = ((RExternalPtr) addressExtract.applyAccessField(frame, symbol, "address")).getAddr();
-        // field name may be "package" or "dll", but always at (R) index 3
-        RList packageList = (RList) packageExtract.apply(frame, symbol, new Object[]{3}, RLogical.valueOf(false), RMissing.instance);
-        DLLInfo dllInfo = (DLLInfo) ((RExternalPtr) addressExtract.applyAccessField(frame, packageList, "info")).getExternalObject();
-        return new NativeCallInfo(name, address, dllInfo);
-
-    }
-
-}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
index c15e41e81848edfec4ae9ad06f1ebbac9a6a7850..b4bf5517d216c83e638f04f7e139142fa7278a16 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java
@@ -11,8 +11,10 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base.foreign;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
@@ -20,11 +22,13 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
 
 public abstract class Fft extends RExternalBuiltinNode.Arg2 {
 
     private final ConditionProfile zVecLgt1 = ConditionProfile.createBinaryProfile();
     private final ConditionProfile noDims = ConditionProfile.createBinaryProfile();
+    @Child private StatsRFFI.FFTNode fftNode = RFFIFactory.getRFFI().getStatsRFFI().createFFTNode();
 
     @Override
     protected void createCasts(CastBuilder casts) {
@@ -34,33 +38,33 @@ public abstract class Fft extends RExternalBuiltinNode.Arg2 {
 
     // TODO: handle more argument types (this is sufficient to run the b25 benchmarks)
     @Specialization
-    public Object execute(RAbstractComplexVector zVec, boolean inverse) {
+    public Object execute(RAbstractComplexVector zVec, boolean inverse, @Cached("create()") GetDimAttributeNode getDimNode) {
         double[] z = zVec.materialize().getDataTemp();
         int inv = inverse ? 2 : -2;
+        int[] d = getDimNode.getDimensions(zVec);
         @SuppressWarnings("unused")
         int retCode = 7;
         if (zVecLgt1.profile(zVec.getLength() > 1)) {
             int[] maxf = new int[1];
             int[] maxp = new int[1];
-            if (noDims.profile(zVec.getDimensions() == null)) {
+            if (noDims.profile(d == null)) {
                 int n = zVec.getLength();
-                RFFIFactory.getRFFI().getStatsRFFI().fft_factor(n, maxf, maxp);
+                fftNode.executeFactor(n, maxf, maxp);
                 if (maxf[0] == 0) {
                     errorProfile.enter();
                     throw RError.error(this, RError.Message.FFT_FACTORIZATION);
                 }
                 double[] work = new double[4 * maxf[0]];
                 int[] iwork = new int[maxp[0]];
-                retCode = RFFIFactory.getRFFI().getStatsRFFI().fft_work(z, 1, n, 1, inv, work, iwork);
+                retCode = fftNode.executeWork(z, 1, n, 1, inv, work, iwork);
             } else {
                 int maxmaxf = 1;
                 int maxmaxp = 1;
-                int[] d = zVec.getDimensions();
                 int ndims = d.length;
                 /* do whole loop just for error checking and maxmax[fp] .. */
                 for (int i = 0; i < ndims; i++) {
                     if (d[i] > 1) {
-                        RFFIFactory.getRFFI().getStatsRFFI().fft_factor(d[i], maxf, maxp);
+                        fftNode.executeFactor(d[i], maxf, maxp);
                         if (maxf[0] == 0) {
                             errorProfile.enter();
                             throw RError.error(this, RError.Message.FFT_FACTORIZATION);
@@ -83,12 +87,12 @@ public abstract class Fft extends RExternalBuiltinNode.Arg2 {
                         nspn *= n;
                         n = d[i];
                         nseg /= n;
-                        RFFIFactory.getRFFI().getStatsRFFI().fft_factor(n, maxf, maxp);
-                        RFFIFactory.getRFFI().getStatsRFFI().fft_work(z, nseg, n, nspn, inv, work, iwork);
+                        fftNode.executeFactor(n, maxf, maxp);
+                        fftNode.executeWork(z, nseg, n, nspn, inv, work, iwork);
                     }
                 }
             }
         }
-        return RDataFactory.createComplexVector(z, zVec.isComplete(), zVec.getDimensions());
+        return RDataFactory.createComplexVector(z, zVec.isComplete(), d);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..abf14d088d7d3deceb19912bb0298050b8343eb5
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java
@@ -0,0 +1,282 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995-2012, The R Core Team
+ * Copyright (c) 2003, The R Foundation
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.nodes.builtin.base.foreign;
+
+import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
+import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
+
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.ffi.CRFFI;
+import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+
+/**
+ * {@code .C} and {@code .Fortran} functions, which share a common signature.
+ *
+ * TODO Completeness (more types, more error checks), Performance (copying). Especially all the
+ * subtleties around copying.
+ *
+ * See <a href="https://stat.ethz.ch/R-manual/R-devel/library/base/html/Foreign.html">here</a>.
+ */
+public class FortranAndCFunctions {
+
+    protected abstract static class CRFFIAdapter extends LookupAdapter {
+        private static final int SCALAR_DOUBLE = 0;
+        private static final int SCALAR_INT = 1;
+        private static final int SCALAR_LOGICAL = 2;
+        @SuppressWarnings("unused") private static final int SCALAR_STRING = 3;
+        private static final int VECTOR_DOUBLE = 10;
+        private static final int VECTOR_INT = 11;
+        private static final int VECTOR_LOGICAL = 12;
+        @SuppressWarnings("unused") private static final int VECTOR_STRING = 12;
+
+        @Child private CRFFI.CRFFINode cRFFINode = RFFIFactory.getRFFI().getCRFFI().createCRFFINode();
+
+        @Override
+        public Object[] getDefaultParameterValues() {
+            return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE, RMissing.instance, RMissing.instance};
+        }
+
+        @TruffleBoundary
+        protected RList dispatch(RBuiltinNode node, NativeCallInfo nativeCallInfo, byte naok, byte dup, RArgsValuesAndNames args) {
+            @SuppressWarnings("unused")
+            boolean dupArgs = RRuntime.fromLogical(dup);
+            @SuppressWarnings("unused")
+            boolean checkNA = RRuntime.fromLogical(naok);
+            // Analyze the args, making copies (ignoring dup for now)
+            Object[] array = args.getArguments();
+            int[] argTypes = new int[array.length];
+            Object[] nativeArgs = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                Object arg = array[i];
+                if (arg instanceof RAbstractDoubleVector) {
+                    argTypes[i] = VECTOR_DOUBLE;
+                    nativeArgs[i] = checkNAs(node, i + 1, ((RAbstractDoubleVector) arg).materialize().getDataCopy());
+                } else if (arg instanceof RAbstractIntVector) {
+                    argTypes[i] = VECTOR_INT;
+                    nativeArgs[i] = checkNAs(node, i + 1, ((RAbstractIntVector) arg).materialize().getDataCopy());
+                } else if (arg instanceof RAbstractLogicalVector) {
+                    argTypes[i] = VECTOR_LOGICAL;
+                    // passed as int[]
+                    byte[] data = ((RAbstractLogicalVector) arg).materialize().getDataWithoutCopying();
+                    int[] dataAsInt = new int[data.length];
+                    for (int j = 0; j < data.length; j++) {
+                        // An NA is an error but the error handling happens in checkNAs
+                        dataAsInt[j] = RRuntime.isNA(data[j]) ? RRuntime.INT_NA : data[j];
+                    }
+                    nativeArgs[i] = checkNAs(node, i + 1, dataAsInt);
+                } else if (arg instanceof Double) {
+                    argTypes[i] = SCALAR_DOUBLE;
+                    nativeArgs[i] = checkNAs(node, i + 1, new double[]{(double) arg});
+                } else if (arg instanceof Integer) {
+                    argTypes[i] = SCALAR_INT;
+                    nativeArgs[i] = checkNAs(node, i + 1, new int[]{(int) arg});
+                } else if (arg instanceof Byte) {
+                    argTypes[i] = SCALAR_LOGICAL;
+                    nativeArgs[i] = checkNAs(node, i + 1, new int[]{RRuntime.isNA((byte) arg) ? RRuntime.INT_NA : (byte) arg});
+                } else {
+                    throw RError.error(node, RError.Message.UNIMPLEMENTED_ARG_TYPE, i + 1);
+                }
+            }
+            cRFFINode.invoke(nativeCallInfo, nativeArgs);
+            // we have to assume that the native method updated everything
+            RStringVector listNames = validateArgNames(array.length, args.getSignature());
+            Object[] results = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                switch (argTypes[i]) {
+                    case SCALAR_DOUBLE:
+                        results[i] = RDataFactory.createDoubleVector((double[]) nativeArgs[i], RDataFactory.COMPLETE_VECTOR);
+                        break;
+                    case SCALAR_INT:
+                        results[i] = RDataFactory.createIntVector((int[]) nativeArgs[i], RDataFactory.COMPLETE_VECTOR);
+                        break;
+                    case SCALAR_LOGICAL:
+                        // have to convert back from int[]
+                        int[] nativeIntArgs = (int[]) nativeArgs[i];
+                        byte[] nativeByteArgs = new byte[nativeIntArgs.length];
+                        for (int j = 0; j < nativeByteArgs.length; j++) {
+                            int nativeInt = nativeIntArgs[j];
+                            nativeByteArgs[j] = (byte) (nativeInt == RRuntime.INT_NA ? RRuntime.LOGICAL_NA : nativeInt & 0xFF);
+                        }
+                        results[i] = RDataFactory.createLogicalVector(nativeByteArgs, RDataFactory.COMPLETE_VECTOR);
+                        break;
+                    case VECTOR_DOUBLE:
+                        results[i] = ((RAbstractDoubleVector) array[i]).materialize().copyResetData((double[]) nativeArgs[i]);
+                        break;
+                    case VECTOR_INT:
+                        results[i] = ((RAbstractIntVector) array[i]).materialize().copyResetData((int[]) nativeArgs[i]);
+                        break;
+                    case VECTOR_LOGICAL: {
+                        int[] intData = (int[]) nativeArgs[i];
+                        byte[] byteData = new byte[intData.length];
+                        for (int j = 0; j < intData.length; j++) {
+                            byteData[j] = RRuntime.isNA(intData[j]) ? RRuntime.LOGICAL_NA : RRuntime.asLogical(intData[j] != 0);
+                        }
+                        results[i] = ((RAbstractLogicalVector) array[i]).materialize().copyResetData(byteData);
+                        break;
+                    }
+                }
+            }
+            return RDataFactory.createList(results, listNames);
+        }
+
+        private static int[] checkNAs(RBuiltinNode node, int argIndex, int[] data) {
+            CompilerAsserts.neverPartOfCompilation();
+            for (int i = 0; i < data.length; i++) {
+                if (RRuntime.isNA(data[i])) {
+                    throw RError.error(node, RError.Message.NA_IN_FOREIGN_FUNCTION_CALL, argIndex);
+                }
+            }
+            return data;
+        }
+
+        private static double[] checkNAs(RBuiltinNode node, int argIndex, double[] data) {
+            CompilerAsserts.neverPartOfCompilation();
+            for (int i = 0; i < data.length; i++) {
+                if (!RRuntime.isFinite(data[i])) {
+                    throw RError.error(node, RError.Message.NA_NAN_INF_IN_FOREIGN_FUNCTION_CALL, argIndex);
+                }
+            }
+            return data;
+        }
+
+        private static RStringVector validateArgNames(int argsLength, ArgumentsSignature signature) {
+            String[] listArgNames = new String[argsLength];
+            for (int i = 0; i < argsLength; i++) {
+                String name = signature.getName(i);
+                if (name == null) {
+                    name = RRuntime.NAMES_ATTR_EMPTY_VALUE;
+                }
+                listArgNames[i] = name;
+            }
+            return RDataFactory.createStringVector(listArgNames, RDataFactory.COMPLETE_VECTOR);
+        }
+
+    }
+
+    /**
+     * Interface to .Fortran native functions. Some functions have explicit implementations in
+     * FastR, otherwise the .Fortran interface uses the machinery that implements the .C interface.
+     */
+    @RBuiltin(name = ".Fortran", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
+    public abstract static class Fortran extends CRFFIAdapter {
+
+        @Override
+        @TruffleBoundary
+        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
+            switch (lookupName(symbol)) {
+                case "dqrdc2":
+                    return new Dqrdc2();
+                case "dqrcf":
+                    return new Dqrcf();
+                default:
+                    return null;
+            }
+        }
+
+        @SuppressWarnings("unused")
+        @Specialization(limit = "1", guards = {"cached == symbol", "builtin != null"})
+        protected Object doExternal(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding, //
+                        @Cached("symbol") RList cached, //
+                        @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin) {
+            return builtin.call(frame, args);
+        }
+
+        @Specialization(guards = "lookupBuiltin(symbol) == null")
+        protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, @SuppressWarnings("unused") Object rPackage,
+                        @SuppressWarnings("unused") RMissing encoding) {
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            return dispatch(this, nativeCallInfo, naok, dup, args);
+        }
+
+        @Specialization
+        protected RList c(RAbstractStringVector symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, @SuppressWarnings("unused") RMissing encoding, //
+                        @Cached("create()") BranchProfile errorProfile) {
+            String libName = checkPackageArg(rPackage, errorProfile);
+            DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Fortran, null, null);
+            DLL.SymbolHandle func = DLL.findSymbol(symbol.getDataAt(0), libName, rns);
+            if (func == DLL.SYMBOL_NOT_FOUND) {
+                errorProfile.enter();
+                throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, symbol);
+            }
+            return dispatch(this, new NativeCallInfo(symbol.getDataAt(0), func, rns.getDllInfo()), naok, dup, args);
+        }
+
+        @SuppressWarnings("unused")
+        @Fallback
+        protected Object fallback(Object symbol, Object args, Object naok, Object dup, Object rPackage, Object encoding) {
+            throw fallback(symbol);
+        }
+    }
+
+    @RBuiltin(name = ".C", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
+    public abstract static class DotC extends CRFFIAdapter {
+
+        @Override
+        @TruffleBoundary
+        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
+            throw RInternalError.shouldNotReachHere();
+        }
+
+        @SuppressWarnings("unused")
+        @Specialization
+        protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding) {
+            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            return dispatch(this, nativeCallInfo, naok, dup, args);
+        }
+
+        @SuppressWarnings("unused")
+        @Specialization
+        protected RList c(RAbstractStringVector symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding, //
+                        @Cached("create()") BranchProfile errorProfile) {
+            String libName = null;
+            if (!(rPackage instanceof RMissing)) {
+                libName = RRuntime.asString(rPackage);
+                if (libName == null) {
+                    errorProfile.enter();
+                    throw RError.error(this, RError.Message.ARGUMENT_MUST_BE_STRING, "PACKAGE");
+                }
+            }
+            DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.C, null, null);
+            DLL.SymbolHandle func = DLL.findSymbol(symbol.getDataAt(0), libName, rns);
+            if (func == DLL.SYMBOL_NOT_FOUND) {
+                errorProfile.enter();
+                throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, symbol);
+            }
+            return dispatch(this, new NativeCallInfo(symbol.getDataAt(0), func, rns.getDllInfo()), naok, dup, args);
+        }
+
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..5da46c93311b5d2f68f85a60ba0b085c4b3539c8
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base.foreign;
+
+import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions;
+import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
+import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.LookupAdapterFactory.ExtractNativeCallInfoNodeGen;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalCode;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.RExternalPtr;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RLogical;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+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;
+
+/**
+ * Locator for "builtin" package function implementations. The "builtin" packages contain many
+ * functions that are called from R code via the FFI, e.g. {@code .Call}, but implemented internally
+ * in GnuR, and not necessarily following the FFI API. The value passed to {@code .Call} etc., is a
+ * symbol, created when the package is loaded and stored in the namespace environment of the
+ * package, that is a list-valued object. Evidently these "builtins" are somewhat similar to the
+ * {@code .Primitive} and {@code .Internal} builtins and, similarly, most of these are
+ * re-implemented in Java in FastR. The {@link #lookupBuiltin(RList)} method checks the name in the
+ * list object and returns the {@link RExternalBuiltinNode} that implements the function, or
+ * {@code null}. A {@code null} result implies that the builtin is not implemented in Java, but
+ * called directly via the FFI interface, which is only possible for functions that use the FFI in a
+ * way that FastR can handle.
+ *
+ * This class also handles the "lookup" of the {@link NativeCallInfo} data for builtins that are
+ * still implemented by native code.
+ */
+abstract class LookupAdapter extends RBuiltinNode {
+    @Child private ExtractNativeCallInfoNode extractSymbolInfoNode = ExtractNativeCallInfoNodeGen.create();
+
+    protected static class UnimplementedExternal extends RExternalBuiltinNode {
+        private final String name;
+
+        public UnimplementedExternal(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public final Object call(RArgsValuesAndNames args) {
+            throw RInternalError.unimplemented("unimplemented external builtin: " + name);
+        }
+    }
+
+    protected abstract RExternalBuiltinNode lookupBuiltin(RList symbol);
+
+    private static final String UNKNOWN_EXTERNAL_BUILTIN = "UNKNOWN_EXTERNAL_BUILTIN";
+
+    protected static String lookupName(RList symbol) {
+        CompilerAsserts.neverPartOfCompilation();
+        if (symbol.getNames() != null) {
+            RAbstractStringVector names = symbol.getNames();
+            for (int i = 0; i < names.getLength(); i++) {
+                if (names.getDataAt(i).equals("name")) {
+                    String name = RRuntime.asString(symbol.getDataAt(i));
+                    return name != null ? name : UNKNOWN_EXTERNAL_BUILTIN;
+                }
+            }
+        }
+        return UNKNOWN_EXTERNAL_BUILTIN;
+    }
+
+    @TruffleBoundary
+    protected RuntimeException fallback(Object symbol) {
+        String name = null;
+        if (symbol instanceof RList) {
+            name = lookupName((RList) symbol);
+            name = name == UNKNOWN_EXTERNAL_BUILTIN ? null : name;
+            if (name != null && lookupBuiltin((RList) symbol) != null) {
+                /*
+                 * if we reach this point, then the cache saw a different value for f. the lists
+                 * that contain the information about native calls are never expected to change.
+                 */
+                throw RInternalError.shouldNotReachHere("fallback reached for " + getRBuiltin().name() + " " + name);
+            }
+        }
+        throw RError.nyi(this, getRBuiltin().name() + " specialization failure: " + (name == null ? "<unknown>" : name));
+    }
+
+    protected NativeCallInfo extractSymbolInfo(VirtualFrame frame, RList symbol) {
+        return (NativeCallInfo) extractSymbolInfoNode.execute(frame, symbol);
+    }
+
+    protected String checkPackageArg(Object rPackage, BranchProfile errorProfile) {
+        String libName = null;
+        if (!(rPackage instanceof RMissing)) {
+            libName = RRuntime.asString(rPackage);
+            if (libName == null) {
+                errorProfile.enter();
+                throw RError.error(this, RError.Message.ARGUMENT_MUST_BE_STRING, "PACKAGE");
+            }
+        }
+        return libName;
+    }
+
+    /**
+     * Extracts the salient information needed for a native call from the {@link RList} value
+     * provided from R.
+     */
+    public abstract static class ExtractNativeCallInfoNode extends Node {
+        @Child private ExtractVectorNode nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+        @Child private ExtractVectorNode addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+        @Child private ExtractVectorNode packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+        @Child private ExtractVectorNode infoExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+
+        protected abstract Object execute(VirtualFrame frame, RList symbol);
+
+        @Specialization
+        protected Object extractNativeCallInfo(VirtualFrame frame, RList symbol) {
+            if (nameExtract == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+            }
+            if (addressExtract == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+            }
+            if (packageExtract == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+            }
+            String name = RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
+            SymbolHandle address = ((RExternalPtr) addressExtract.applyAccessField(frame, symbol, "address")).getAddr();
+            // field name may be "package" or "dll", but always at (R) index 3
+            RList packageList = (RList) packageExtract.apply(frame, symbol, new Object[]{3}, RLogical.valueOf(false), RMissing.instance);
+            DLLInfo dllInfo = (DLLInfo) ((RExternalPtr) addressExtract.applyAccessField(frame, packageList, "info")).getExternalObject();
+            return new NativeCallInfo(name, address, dllInfo);
+
+        }
+    }
+
+    protected static RExternalBuiltinNode getExternalModelBuiltinNode(String name) {
+        return new RInternalCodeBuiltinNode(RContext.getInstance(), "stats", RInternalCode.loadSourceRelativeTo(RandGenerationFunctions.class, "model.R"), name);
+    }
+
+    protected static final int CallNST = DLL.NativeSymbolType.Call.ordinal();
+    protected static final int ExternalNST = DLL.NativeSymbolType.External.ordinal();
+
+    public static DLL.RegisteredNativeSymbol createRegisteredNativeSymbol(int nstOrd) {
+        // DSL cannot resolve DLL.DLL.NativeSymbolType
+        DLL.NativeSymbolType nst = DLL.NativeSymbolType.values()[nstOrd];
+        return new DLL.RegisteredNativeSymbol(nst, null, null);
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java
index 36866074464c2b3f440152f76350d05a393b6dbc..9f848c51562ad640a6ac5c7331ebdd9be1c13c2b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java
@@ -39,6 +39,7 @@ import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractListElement;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
@@ -69,8 +70,8 @@ abstract class AccessFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
     }
 
     @Specialization(contains = "doList", guards = {"isSimpleList(list)", "list.getNames() != null"})
-    public Object doListDynamic(RList list, String field) {
-        return doList(list, field, getIndex(list.getNames(), field));
+    public Object doListDynamic(RList list, String field, @Cached("create()") GetNamesAttributeNode getNamesNode) {
+        return doList(list, field, getIndex(getNamesNode.getNames(list), field));
     }
 
     @Fallback
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java
index a72d60cf059516649d731875c9f2352777135446..793d882e1a8121d8e29bcbdbcd993e9b78bbe6d3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/SpecialsUtils.java
@@ -26,6 +26,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -84,12 +85,13 @@ class SpecialsUtils {
         @CompilationFinal private String cachedField;
         @CompilationFinal private RStringVector cachedNames;
         @Child private ClassHierarchyNode hierarchyNode = ClassHierarchyNode.create();
+        @Child protected GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
         protected final void updateCache(RList list, String field) {
             if (cachedField == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 cachedField = field;
-                cachedNames = list.getNames();
+                cachedNames = getNamesNode.getNames(list);
             }
         }
 
@@ -98,7 +100,7 @@ class SpecialsUtils {
         }
 
         protected final boolean isCached(RList list, String field) {
-            return cachedField == null || (cachedField == field && list.getNames() == cachedNames);
+            return cachedField == null || (cachedField == field && getNamesNode.getNames(list) == cachedNames);
         }
 
         protected static int getIndex(RStringVector names, String field) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
index 4b3166024df80800419b87a3ec2843f9f62f46b7..9d693de22845ef0dba043d41824103eeda08015e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
@@ -34,12 +34,12 @@ import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ExtractListElement;
 import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogical;
@@ -55,12 +55,12 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 @TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 abstract class SubsetSpecial extends SubscriptSpecialBase {
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     @Override
     protected boolean simpleVector(RAbstractVector vector) {
         vector = vectorClassProfile.profile(vector);
-        return super.simpleVector(vector) && vector.getNames(attrProfiles) == null;
+        return super.simpleVector(vector) && getNamesNode.getNames(vector) == null;
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
index 771bc4bd590e1e2d170aacb2159ceca8c77d16c5..1918c7c7447a23370355b722e6bcf4ba139faeb0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
@@ -25,8 +25,11 @@ package com.oracle.truffle.r.nodes.builtin.base.infix;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_FRAME;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.RCallNode;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -49,18 +52,25 @@ public abstract class Tilde extends RBuiltinNode {
 
     private static final RStringVector FORMULA_CLASS = RDataFactory.createStringVectorFromScalar(RRuntime.FORMULA_CLASS);
 
+    @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RMissing.instance, RMissing.instance};
     }
 
+    protected SetFixedAttributeNode createSetEnvAttrNode() {
+        return SetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT);
+    }
+
     @Specialization
-    protected RLanguage tilde(VirtualFrame frame, @SuppressWarnings("unused") Object response, @SuppressWarnings("unused") Object model) {
+    protected RLanguage tilde(VirtualFrame frame, @SuppressWarnings("unused") Object response, @SuppressWarnings("unused") Object model,
+                    @Cached("createSetEnvAttrNode()") SetFixedAttributeNode setEnvAttrNode) {
         RCallNode call = (RCallNode) ((RBaseNode) getParent()).asRSyntaxNode();
         RLanguage lang = RDataFactory.createLanguage(call);
-        lang.setClassAttr(FORMULA_CLASS);
+        setClassAttrNode.execute(lang, FORMULA_CLASS);
         REnvironment env = REnvironment.frameToEnvironment(frame.materialize());
-        lang.setAttr(RRuntime.DOT_ENVIRONMENT, env);
+        setEnvAttrNode.execute(lang, env);
         return lang;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java
index da44b6344da226739efbb89c77cbb9067773ccbe..ebbd01a056c1e63bb5e0436186690bb062b07a2c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateField.java
@@ -83,7 +83,7 @@ abstract class UpdateFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
 
     @Specialization(contains = "doList", guards = {"isSimpleList(list)", "!list.isShared()", "list.getNames() != null", "isNotRNullRList(value)"})
     public RList doListDynamic(RList list, String field, Object value) {
-        return doList(list, field, value, getIndex(list.getNames(), field));
+        return doList(list, field, value, getIndex(getNamesNode.getNames(list), field));
     }
 
     @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java
index d8fcdd5d2926f7fbae17bbc8913cc2097940d3e5..6bbd827d0354c7ff5428f5c4a1bc7a1fbb82a087 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java
@@ -26,8 +26,6 @@ import java.io.IOException;
 import java.io.PrintWriter;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
@@ -39,8 +37,6 @@ final class ExpressionPrinter extends AbstractValuePrinter<RExpression> {
         // singleton
     }
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     @Override
     @TruffleBoundary
     protected void printValue(RExpression expr, PrintContext printCtx) throws IOException {
@@ -49,7 +45,7 @@ final class ExpressionPrinter extends AbstractValuePrinter<RExpression> {
         valPrintCtx.parameters().setSuppressIndexLabels(true);
 
         out.print("expression(");
-        RStringVector names = (RStringVector) expr.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY);
+        RStringVector names = expr.getNames();
         for (int i = 0; i < expr.getLength(); i++) {
             if (i != 0) {
                 out.print(", ");
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
index ffc0c1db1b5e9877d742687455e746f049aa7cb3..62a994e753e86d30a52158f32994a1dbba4891ae 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
@@ -44,20 +44,19 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
 
     static final ListPrinter INSTANCE = new ListPrinter();
+    private static final RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
 
     private ListPrinter() {
         // singleton
     }
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     private static int TAGBUFLEN = 256;
 
     @Override
     @TruffleBoundary
     protected void printValue(RAbstractListVector s, PrintContext printCtx) throws IOException {
         RAbstractIntVector dims = Utils.<RAbstractIntVector> castTo(
-                        s.getAttr(dummyAttrProfiles, RRuntime.DIM_ATTR_KEY));
+                        s.getAttr(RRuntime.DIM_ATTR_KEY));
 
         if (dims != null && dims.getLength() > 1) {
             printDimList(s, printCtx);
@@ -151,7 +150,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
         }
 
         RStringVector tt = RDataFactory.createStringVector(t, true, s.getDimensions());
-        Object dimNames = s.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY);
+        Object dimNames = s.getAttr(RRuntime.DIMNAMES_ATTR_KEY);
         tt.setAttr(RRuntime.DIMNAMES_ATTR_KEY, dimNames);
 
         PrintContext cc = printCtx.cloneContext();
@@ -171,7 +170,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
         int ns = s.getLength();
 
         RAbstractStringVector names;
-        names = Utils.castTo(RRuntime.asAbstractVector(s.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY)));
+        names = Utils.castTo(RRuntime.asAbstractVector(s.getNames(dummyAttrProfiles)));
 
         if (ns > 0) {
             int npr = (ns <= pp.getMax() + 1) ? ns : pp.getMax();
@@ -216,7 +215,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
 
                 out.println(tagbuf);
                 Object si = s.getDataAtAsObject(i);
-                if (si instanceof RAttributable && ((RAttributable) si).isObject(dummyAttrProfiles)) {
+                if (si instanceof RAttributable && ((RAttributable) si).isObject()) {
                     RContext.getEngine().printResult(si);
                 } else {
                     ValuePrinters.INSTANCE.print(si, printCtx);
@@ -236,7 +235,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
             /* Formal classes are represented as empty lists */
             String className = null;
             if (printCtx.printerNode().isObject(s) && printCtx.printerNode().isMethodDispatchOn()) {
-                RAbstractStringVector klass = Utils.castTo(RRuntime.asAbstractVector(s.getAttr(dummyAttrProfiles, RRuntime.CLASS_ATTR_KEY)));
+                RAbstractStringVector klass = Utils.castTo(RRuntime.asAbstractVector(s.getAttr(RRuntime.CLASS_ATTR_KEY)));
                 if (klass != null && klass.getLength() == 1) {
                     String ss = klass.getDataAt(0);
                     String str = snprintf(200, ".__C__%s", ss);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
index 9dabad114d57463555f70c483b5dbc381a9abc9b..5927ddf98ec477d3b0d8c3dc191785040e0831f2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
@@ -17,7 +17,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -42,13 +41,11 @@ final class PairListPrinter extends AbstractValuePrinter<RPairList> {
         // singleton
     }
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     @Override
     @TruffleBoundary
     protected void printValue(RPairList s, PrintContext printCtx) throws IOException {
         final RAbstractIntVector dims = Utils.<RAbstractIntVector> castTo(
-                        s.getAttr(dummyAttrProfiles, RRuntime.DIM_ATTR_KEY));
+                        s.getAttr(RRuntime.DIM_ATTR_KEY));
 
         final int ns = s.getLength();
 
@@ -82,7 +79,7 @@ final class PairListPrinter extends AbstractValuePrinter<RPairList> {
                 t[i] = pbuf;
 
                 RStringVector tt = RDataFactory.createStringVector(t, true, s.getDimensions());
-                Object dimNames = s.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY);
+                Object dimNames = s.getAttr(RRuntime.DIMNAMES_ATTR_KEY);
                 tt.setAttr(RRuntime.DIMNAMES_ATTR_KEY, dimNames);
 
                 PrintContext cc = printCtx.cloneContext();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
index cbcb5e2af91c4a3884b2f87f57ca61a10498684b..7448ebc7516c8ea623afd1c3ca912f86528212e5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
@@ -542,7 +542,7 @@ public final class ValuePrinterNode extends RBaseNode {
         }
 
         @Override
-        public void setNames(RStringVector newNames) {
+        public final void setNames(RStringVector newNames) {
             throw RInternalError.shouldNotReachHere();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
index dcbc682204eda47037bf0d17c584f364f162973f..5577dd7c283cd4f934d3edcdee26c1a71687af24 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
@@ -19,7 +19,6 @@ import java.io.PrintWriter;
 
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -29,8 +28,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePrinter<T> {
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     @Override
     protected void printValue(T vector, PrintContext printCtx) throws IOException {
         printVector(vector, 1, printCtx);
@@ -77,13 +74,13 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
 
             MatrixDimNames mdn = null;
 
-            Object dimAttr = vector.getAttr(dummyAttrProfiles, RRuntime.DIM_ATTR_KEY);
+            Object dimAttr = vector.getAttr(RRuntime.DIM_ATTR_KEY);
             if (dimAttr instanceof RAbstractIntVector) {
                 dims = (RAbstractIntVector) dimAttr;
                 if (dims.getLength() == 1) {
-                    RList t = Utils.<RList> castTo(vector.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY));
+                    RList t = Utils.<RList> castTo(vector.getAttr(RRuntime.DIMNAMES_ATTR_KEY));
                     if (t != null && t.getDataAt(0) != null) {
-                        RAbstractStringVector nn = Utils.castTo(RRuntime.asAbstractVector(t.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY)));
+                        RAbstractStringVector nn = Utils.castTo(RRuntime.asAbstractVector(t.getNames()));
 
                         if (nn != null) {
                             title = nn.getDataAt(0);
@@ -111,7 +108,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                 }
             } else {
                 dims = null;
-                Object namesAttr = Utils.castTo(vector.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY));
+                Object namesAttr = Utils.castTo(vector.getAttr(RRuntime.NAMES_ATTR_KEY));
                 if (namesAttr != null) {
                     if (vector.getLength() > 0) {
                         names = Utils.castTo(RRuntime.asAbstractVector(namesAttr));
@@ -676,7 +673,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
         final RAbstractStringVector axisNames;
 
         MatrixDimNames(RAbstractVector x) {
-            dimnames = Utils.<RList> castTo(x.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY));
+            dimnames = Utils.<RList> castTo(x.getAttr(RRuntime.DIMNAMES_ATTR_KEY));
 
             if (dimnames == null) {
                 rl = null;
@@ -688,7 +685,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
             } else {
                 rl = getDimNamesAt(0);
                 cl = getDimNamesAt(1);
-                axisNames = Utils.<RAbstractStringVector> castTo(dimnames.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY));
+                axisNames = Utils.<RAbstractStringVector> castTo(dimnames.getNames());
                 if (axisNames == null) {
                     rn = null;
                     cn = null;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
index 4a6ededba9b6103720b5e7d49202ec778b612c6e..dd68c15f3a66753ccf27bed53273331db337bcf7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
@@ -192,7 +192,11 @@ public class FastRContext {
             if (pc == 1) {
                 ContextInfo info = createContextInfo(contextKind);
                 PolyglotEngine vm = info.createVM();
-                results[0] = RContext.EvalThread.run(vm, info, RSource.fromTextInternal(exprs.getDataAt(0), RSource.Internal.CONTEXT_EVAL));
+                try {
+                    results[0] = RContext.EvalThread.run(vm, info, RSource.fromTextInternal(exprs.getDataAt(0), RSource.Internal.CONTEXT_EVAL));
+                } finally {
+                    vm.dispose();
+                }
             } else {
                 // separate threads that run in parallel; invoking thread waits for completion
                 RContext.EvalThread[] threads = new RContext.EvalThread[pc];
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java
index 071ef08d2a93304f80ef7f32d0c3661722fef431..315f1f2c0aad2161732c7d25cb6d09620e3a958d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.RCallBaseNode;
 import com.oracle.truffle.r.nodes.function.RCallNode;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -55,7 +56,7 @@ public abstract class FastRTry extends RBuiltinNode {
             frame.setObject(frameSlot, RArgsValuesAndNames.EMPTY);
             call.execute(frame, func);
         } catch (Throwable ex) {
-            return String.format("Exception %s, message: %s", ex.getClass().getSimpleName(), ex.getMessage());
+            return Utils.stringFormat("Exception %s, message: %s", ex.getClass().getSimpleName(), ex.getMessage());
         } finally {
             frame.setObject(frameSlot, null);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java
index 07719a305b4ca2937b7dbd2d4a5cb64eddebc9b0..714e8c2a381a8dd49dd583944e2439d4e5d3ef7d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastrDqrls.java
@@ -23,13 +23,13 @@ import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.ffi.RApplRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 /**
@@ -38,14 +38,11 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
  */
 @RBuiltin(name = ".fastr.dqrls", visibility = OFF, kind = PRIMITIVE, parameterNames = {"x", "n", "p", "y", "ny", "tol", "coeff"}, behavior = PURE)
 public abstract class FastrDqrls extends RBuiltinNode {
+    @Child private RApplRFFI.RApplRFFINode rApplRFFINode = RFFIFactory.getRFFI().getRApplRFFI().createRApplRFFINode();
 
     private static final String[] NAMES = new String[]{"qr", "coefficients", "residuals", "effects", "rank", "pivot", "qraux", "tol", "pivoted"};
     private static RStringVector namesVector = null;
 
-    private final RAttributeProfiles coeffAttributeProfiles = RAttributeProfiles.create();
-    private final RAttributeProfiles xAttributeProfiles = RAttributeProfiles.create();
-    private final RAttributeProfiles residualsAttributesProfiles = RAttributeProfiles.create();
-
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("x").asDoubleVector(true, true, true);
@@ -82,16 +79,16 @@ public abstract class FastrDqrls extends RBuiltinNode {
             pivot[i] = i + 1;
         }
 
-        RFFIFactory.getRFFI().getRApplRFFI().dqrls(x, n, p, y, ny, tol, coeff, residuals, effects, rank, pivot, qraux, work);
+        rApplRFFINode.dqrls(x, n, p, y, ny, tol, coeff, residuals, effects, rank, pivot, qraux, work);
 
         RDoubleVector resultCoeffVect = RDataFactory.createDoubleVector(coeff, RDataFactory.COMPLETE_VECTOR);
-        resultCoeffVect.copyAttributesFrom(coeffAttributeProfiles, coeffVec);
+        resultCoeffVect.copyAttributesFrom(coeffVec);
 
         RDoubleVector resultX = RDataFactory.createDoubleVector(x, RDataFactory.COMPLETE_VECTOR);
-        resultX.copyAttributesFrom(xAttributeProfiles, originalXVec);
+        resultX.copyAttributesFrom(originalXVec);
 
         RDoubleVector resultResiduals = RDataFactory.createDoubleVector(residuals, RDataFactory.COMPLETE_VECTOR);
-        resultResiduals.copyAttributesFrom(residualsAttributesProfiles, originalYVec);
+        resultResiduals.copyAttributesFrom(originalYVec);
 
         Object[] data = new Object[]{
                         resultX,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
index 044773513f6598af456b3be185fda9108d69737c..78c4fd48204f108f6fb44bc9d9ff2eaa70ff7f1c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
@@ -27,6 +27,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -69,6 +70,9 @@ public abstract class BrowserInteractNode extends RNode {
     public static final int CONTINUE = 2;
     public static final int FINISH = 3;
 
+    @Child private GetFixedAttributeNode getSrcRefAttrNode;
+    @Child private GetFixedAttributeNode getSrcFileAttrNode;
+
     @Specialization
     protected int interact(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreter();
@@ -179,11 +183,20 @@ public abstract class BrowserInteractNode extends RNode {
         return RCaller.create(null, currentCaller, builder.call(RSyntaxNode.INTERNAL, builder.lookup(RSyntaxNode.INTERNAL, "browser", true)));
     }
 
-    private static String getSrcinfo(RStringVector element) {
-        Object srcref = element.getAttr(RRuntime.R_SRCREF);
+    private String getSrcinfo(RStringVector element) {
+        if (getSrcRefAttrNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getSrcRefAttrNode = insert(GetFixedAttributeNode.create(RRuntime.R_SRCREF));
+        }
+
+        Object srcref = getSrcRefAttrNode.execute(element);
         if (srcref != null) {
+            if (getSrcFileAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getSrcFileAttrNode = insert(GetFixedAttributeNode.create(RRuntime.R_SRCFILE));
+            }
             RIntVector lloc = (RIntVector) srcref;
-            Object srcfile = lloc.getAttr(RRuntime.R_SRCFILE);
+            Object srcfile = getSrcFileAttrNode.execute(lloc);
             if (srcfile != null) {
                 REnvironment env = (REnvironment) srcfile;
                 return " at " + RRuntime.asString(env.get(RSrcref.SrcrefFields.filename.name())) + "#" + lloc.getDataAt(0);
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java
index d17626bd61f79b6c3f08b544914cebc5fdca54c1..b0e55a5d0192eea5ba7efba7987f15b82d589f6f 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java
@@ -64,7 +64,6 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import java.util.function.Consumer;
 import java.util.function.Function;
 
 import org.junit.After;
@@ -75,7 +74,6 @@ import org.junit.Test;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineConfig;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.InitialPhaseBuilder;
-import com.oracle.truffle.r.nodes.builtin.casts.fluent.PipelineConfigBuilder;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.PreinitialPhaseBuilder;
 import com.oracle.truffle.r.nodes.casts.CastNodeSampler;
 import com.oracle.truffle.r.nodes.casts.FilterSamplerFactory;
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
index 668afbfc228cf49e199438f87a448f9b7ef0b88f..ce538982b09d76218ae36524e3cb873e9f26cc20 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
@@ -67,7 +67,6 @@ import com.oracle.truffle.r.nodes.binary.BinaryArithmeticNode;
 import com.oracle.truffle.r.nodes.test.TestUtilities.NodeHandle;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java
index d231d368106ff91a044eb2fe90e2f943d1213b0c..5a7ef2b6e1eeb41b379c803ec9e26d2326f66b67 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java
@@ -56,7 +56,6 @@ import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNodeGen;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RSequence;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
index 50b84824a122ebfa9b012e38dfe7807e58e57518..e5307e12f2b19f3d435dc30d25e7b497556d3231 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
@@ -21,7 +21,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
@@ -42,6 +41,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
+// Transcribed from src/main/attrib.c file (R_do_slot function)
+
 /**
  * Perform a slot access. This node represents the {@code @} operator in R.
  */
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
index c0b37f806041ee648bfecb8dccf76df73f04f3ec..22972c305937af31631bec8b43d876dadfb1b80f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
@@ -18,7 +18,6 @@ import com.oracle.truffle.api.dsl.NodeChild;
 import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.RASTUtils;
-import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -31,6 +30,8 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
+// Transcribed from src/main/attrib.c file (R_do_slot_assign function)
+
 @NodeChildren({@NodeChild(value = "object", type = RNode.class), @NodeChild(value = "name", type = RNode.class), @NodeChild(value = "value", type = RNode.class)})
 public abstract class UpdateSlotNode extends RNode {
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
index 9013ee971727f511d890c57a113796f664921721..589acd316b992ddc87812d2e6fb7306c88c4562d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
@@ -33,7 +33,10 @@ import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.vector.CachedExtractVectorNodeFactory.SetNamesNodeGen;
 import com.oracle.truffle.r.nodes.access.vector.PositionsCheckNode.PositionProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -69,11 +72,15 @@ final class CachedExtractVectorNode extends CachedVectorNode {
     private final boolean dropDimensions;
 
     private final VectorLengthProfile vectorLengthProfile = VectorLengthProfile.create();
-    private final RAttributeProfiles vectorNamesProfile = RAttributeProfiles.create();
 
     @Child private WriteIndexedVectorNode writeVectorNode;
     @Child private PositionsCheckNode positionsCheckNode;
     @Child private SetNamesNode setNamesNode;
+    @Child private SetDimAttributeNode setDimNode;
+    @Child private SetDimNamesAttributeNode setDimNamesNode;
+    @Child private GetDimNamesAttributeNode getDimNamesNode;
+    @Child private GetNamesAttributeNode getNamesNode;
+    @Child private GetNamesAttributeNode getNamesFromDimNamesNode;
     @Children private final CachedExtractVectorNode[] extractNames;
     @Children private final CachedExtractVectorNode[] extractNamesAlternative;
 
@@ -185,7 +192,11 @@ final class CachedExtractVectorNode extends CachedVectorNode {
             }
             if (oneDimensionProfile.profile(numberOfDimensions == 1)) {
                 // names only need to be considered for single dimensional accesses
-                RStringVector originalNames = vector.getNames(vectorNamesProfile);
+                if (getNamesNode == null) {
+                    CompilerDirectives.transferToInterpreter();
+                    getNamesNode = insert(GetNamesAttributeNode.create());
+                }
+                RStringVector originalNames = getNamesNode.getNames(vector);
                 if (originalNames != null) {
                     metadataApplied.enter();
                     setNames(extractedVector, extractNames(originalNames, positions, positionProfiles, 0, originalExact, originalDropDimensions));
@@ -274,7 +285,6 @@ final class CachedExtractVectorNode extends CachedVectorNode {
     }
 
     private final ConditionProfile dimNamesNull = ConditionProfile.createBinaryProfile();
-    private final RAttributeProfiles dimnamesNamesProfile = RAttributeProfiles.create();
     private final ValueProfile foundDimNamesProfile = ValueProfile.createClassProfile();
     private final ConditionProfile selectPositionsProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile originalDimNamesPRofile = ConditionProfile.createBinaryProfile();
@@ -285,8 +295,13 @@ final class CachedExtractVectorNode extends CachedVectorNode {
         // TODO speculate on the number of counted dimensions
         int dimCount = countDimensions(positionProfile);
 
+        if (getDimNamesNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getDimNamesNode = insert(GetDimNamesAttributeNode.create());
+        }
+
         int[] newDimensions = new int[dimCount];
-        RList originalDimNames = originalTarget.getDimNames(null);
+        RList originalDimNames = getDimNamesNode.getDimNames(originalTarget);
         RStringVector originalDimNamesNames;
         Object[] newDimNames;
         String[] newDimNamesNames;
@@ -295,8 +310,12 @@ final class CachedExtractVectorNode extends CachedVectorNode {
             originalDimNamesNames = null;
             newDimNamesNames = null;
         } else {
+            if (getNamesFromDimNamesNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getNamesFromDimNamesNode = insert(GetNamesAttributeNode.create());
+            }
             newDimNames = new Object[dimCount];
-            originalDimNamesNames = originalDimNames.getNames(dimnamesNamesProfile);
+            originalDimNamesNames = getNamesFromDimNamesNode.getNames(originalDimNames);
             newDimNamesNames = originalDimNamesNames == null ? null : new String[dimCount];
         }
 
@@ -326,9 +345,20 @@ final class CachedExtractVectorNode extends CachedVectorNode {
 
         if (resultHasDimensions.profile(dimCount > 1)) {
             metadataApplied.enter();
-            extractedTarget.setDimensions(newDimensions);
+
+            if (setDimNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setDimNode = insert(SetDimAttributeNode.create());
+            }
+
+            setDimNode.setDimensions(extractedTarget, newDimensions);
             if (newDimNames != null) {
-                extractedTarget.setDimNames(RDataFactory.createList(newDimNames, newDimNamesNames == null ? null : RDataFactory.createStringVector(newDimNamesNames, originalDimNames.isComplete())));
+                if (setDimNamesNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    setDimNamesNode = insert(SetDimNamesAttributeNode.create());
+                }
+                setDimNamesNode.setDimNames(extractedTarget,
+                                RDataFactory.createList(newDimNames, newDimNamesNames == null ? null : RDataFactory.createStringVector(newDimNamesNames, originalDimNames.isComplete())));
             }
         } else if (newDimNames != null && originalDimNamesPRofile.profile(originalDimNames.getLength() > 0)) {
             RAbstractStringVector foundNames = translateDimNamesToNames(positionProfile, originalDimNames, extractedTargetLength, positions);
@@ -445,7 +475,6 @@ final class CachedExtractVectorNode extends CachedVectorNode {
             if (container.getAttributes() == null) {
                 // usual case
                 container.initAttributes(RAttributesLayout.createNames(newNames1));
-                container.setInternalNames(newNames1);
             } else {
                 // from an RLanguage extraction that set a name
                 RStringVector oldNames = (RStringVector) namesAttrGetter.execute(container.getAttributes());
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
index e951c3c9927316606423f3d313152a0bc252a6c4..2113155262a366925b79e1963772fda9a23f2806 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java
@@ -40,6 +40,8 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.vector.CachedReplaceVectorNodeFactory.ValueProfileNodeGen;
 import com.oracle.truffle.r.nodes.access.vector.PositionsCheckNode.PositionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.nodes.unary.CastListNodeGen;
@@ -79,7 +81,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
     private final VectorLengthProfile valueLengthProfile = VectorLengthProfile.create();
     private final BranchProfile warningBranch = BranchProfile.create();
     private final RAttributeProfiles vectorNamesProfile = RAttributeProfiles.create();
-    private final RAttributeProfiles positionNamesProfile = RAttributeProfiles.create();
     private final ConditionProfile valueIsNA = ConditionProfile.createBinaryProfile();
     private final BranchProfile resizeProfile = BranchProfile.create();
     private final BranchProfile sharedProfile = BranchProfile.create();
@@ -100,6 +101,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
     @Child private CastNode castVectorNode;
     @Child private CachedReplaceVectorNode copyPositionNames;
     @Child private DeleteElementsNode deleteElementsNode;
+    @Child private SetNamesAttributeNode setNamesNode;
 
     CachedReplaceVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, RTypedValue value, boolean updatePositionNames, boolean recursive) {
         super(mode, vector, positions, recursive);
@@ -438,6 +440,8 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
     }
 
     private final ValueProfile positionCastProfile = ValueProfile.createClassProfile();
+    @Child private GetNamesAttributeNode getNamesNode;
+    @Child private GetNamesAttributeNode getResultNamesNode;
 
     private void updateVectorWithPositionNames(RAbstractVector vector, Object[] positions) {
         Object position = positionCastProfile.profile(positions[0]);
@@ -446,7 +450,11 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         if (position instanceof RMissing) {
             positionNames = null;
         } else {
-            positionNames = ((RAbstractVector) position).getNames(positionNamesProfile);
+            if (getNamesNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getNamesNode = insert(GetNamesAttributeNode.create());
+            }
+            positionNames = getNamesNode.getNames(position);
         }
         if (positionNames != null && positionNames.getLength() > 0) {
             updatePositionNames(vector, positionNames, positions);
@@ -537,7 +545,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         RStringVector oldNames = vector.getNames(vectorNamesProfile);
         RVector<?> res = vector.copyResized(size, true).materialize();
         if (vector instanceof RVector) {
-            res.copyAttributesFrom(positionNamesProfile, vector);
+            res.copyAttributesFrom(vector);
         }
         res.setDimensionsNoCheck(null);
         res.setDimNamesNoCheck(null);
@@ -551,7 +559,11 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
     private final ConditionProfile updateNamesProfile = ConditionProfile.createBinaryProfile();
 
     private void updatePositionNames(RAbstractVector resultVector, RAbstractStringVector positionNames, Object[] positions) {
-        RTypedValue originalNames = resultVector.getNames(positionNamesProfile);
+        if (getResultNamesNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getResultNamesNode = insert(GetNamesAttributeNode.create());
+        }
+        RTypedValue originalNames = getResultNamesNode.getNames(resultVector);
         RTypedValue names = originalNames;
         if (names == null) {
             String[] emptyVector = new String[resultVector.getLength()];
@@ -565,7 +577,11 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
         assert copyPositionNames.isSupported(names, positions, positionNames);
         RAbstractStringVector newNames = (RAbstractStringVector) copyPositionNames.apply(names, positions, positionNames);
         if (updateNamesProfile.profile(newNames != originalNames)) {
-            resultVector.setNames(newNames.materialize());
+            if (setNamesNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setNamesNode = insert(SetNamesAttributeNode.create());
+            }
+            setNamesNode.setNames(resultVector, newNames.materialize());
         }
     }
 
@@ -580,7 +596,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
          */
         @CompilationFinal private int previousResultLength = PREVIOUS_RESULT_UNINITIALIZED;
 
-        private final RAttributeProfiles vectorNamesProfile = RAttributeProfiles.create();
+        @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
         public RAbstractVector deleteElements(RAbstractVector vector, int vectorLength) {
             // we can speculate here that we delete always the same number of elements
@@ -596,7 +612,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
             }
 
             Object[] data = new Object[resultLength];
-            RStringVector names = vector.getNames(vectorNamesProfile);
+            RStringVector names = getNamesNode.getNames(vector);
             boolean hasNames = names != null;
             String[] newNames = null;
             if (hasNames) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java
index 2622dfc83ebb23d9920416d187264533e4ce06fe..ddd61957c7c5e09b7df428161eff08cd00e3ace4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.access.vector;
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
@@ -60,6 +61,8 @@ abstract class CachedVectorNode extends RBaseNode {
     // if this is non-null, the node needs to throw the error whenever it is executed
     @CompilationFinal protected Runnable error;
 
+    @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create();
+
     CachedVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, boolean recursive) {
         this.mode = mode;
         this.vectorType = vector.getRType();
@@ -151,14 +154,13 @@ abstract class CachedVectorNode extends RBaseNode {
         }
     }
 
-    @SuppressWarnings("static-method")
     protected final int[] loadVectorDimensions(RAbstractContainer vector) {
         // N.B. (stepan) this method used to be instance method and have special handling for
         // RDataFrame, which was removed and any test case, which would require this special
         // handling was not found (see TestBuiltin_extract_dataframe for tests used and further
         // explanation). This method and note will remain here for a while in case this behavior
         // crops up somewhere
-        return vector.getDimensions();
+        return getDimNode.getDimensions(vector);
     }
 
     public ElementAccessMode getMode() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java
index e437eef25787fc36433b988c3109a99dcd04ba6b..70e086e85722e0917405de4db7f6f82244cd5526 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java
@@ -24,9 +24,10 @@ package com.oracle.truffle.r.nodes.access.vector;
 
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -38,12 +39,13 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 final class PositionCharacterLookupNode extends Node {
 
     private final ElementAccessMode mode;
-    private final RAttributeProfiles attributeProfiles = RAttributeProfiles.create();
     private final int numDimensions;
     private final int dimensionIndex;
     private final BranchProfile emptyProfile = BranchProfile.create();
 
     @Child private SearchFirstStringNode searchNode;
+    @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     PositionCharacterLookupNode(ElementAccessMode mode, int numDimensions, int dimensionIndex, boolean useNAForNotFound, boolean exact) {
         this.numDimensions = numDimensions;
@@ -56,14 +58,14 @@ final class PositionCharacterLookupNode extends Node {
         // lookup names for single dimension case
         RAbstractIntVector result;
         if (numDimensions <= 1) {
-            RStringVector names = target.getNames(attributeProfiles);
+            RStringVector names = getNamesNode.getNames(target);
             if (names == null) {
                 emptyProfile.enter();
                 names = RDataFactory.createEmptyStringVector();
             }
             result = searchNode.apply(names, position, notFoundStartIndex, position.materialize());
         } else {
-            RList dimNames = target.getDimNames(attributeProfiles);
+            RList dimNames = getDimNamesNode.getDimNames(target);
             if (dimNames != null) {
                 Object dataAt = dimNames.getDataAt(dimensionIndex);
                 if (dataAt != RNull.instance) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckNode.java
index 5ec428e5feefa3341125319e430de02631d25336..9dffa7e5111fdd7459b8c5f77352b2daa85eed54 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckNode.java
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.vector.PositionCheckNodeFactory.Mat2indsubNodeGen;
 import com.oracle.truffle.r.nodes.access.vector.PositionsCheckNode.PositionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -110,6 +111,8 @@ abstract class PositionCheckNode extends Node {
     }
 
     @Child private Mat2indsubNode mat2indsub;
+    @Child private GetDimAttributeNode getVectorDimsNode;
+    @Child private GetDimAttributeNode getVectorPosDimsNode;
 
     public final Object execute(PositionProfile profile, RAbstractContainer vector, int[] vectorDimensions, int vectorLength, Object position) {
         Object castPosition = castNode.execute(positionClass.cast(position));
@@ -124,12 +127,20 @@ abstract class PositionCheckNode extends Node {
         }
 
         if (mode.isSubset() && numDimensions == 1) {
-            int[] vectorDim = vector.getDimensions();
+            if (getVectorDimsNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getVectorDimsNode = insert(GetDimAttributeNode.create());
+            }
+            int[] vectorDim = getVectorDimsNode.getDimensions(vector);
             if (nullDimensionsProfile.profile(vectorDim != null) && vectorDim.length == 2) {
                 if (vector instanceof RAbstractVector && ((RAbstractVector) vector).isArray()) {
                     if (castPosition instanceof RAbstractVector) {
+                        if (getVectorPosDimsNode == null) {
+                            CompilerDirectives.transferToInterpreterAndInvalidate();
+                            getVectorPosDimsNode = insert(GetDimAttributeNode.create());
+                        }
                         RAbstractVector vectorPosition = (RAbstractVector) castPosition;
-                        int[] posDim = vectorPosition.getDimensions();
+                        int[] posDim = getVectorPosDimsNode.getDimensions(vectorPosition);
                         if (posDim != null && posDim.length == 2 && posDim[1] == vectorDim.length) {
                             if (castPosition instanceof RAbstractIntVector || castPosition instanceof RAbstractDoubleVector) {
                                 if (mat2indsub == null) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubscriptNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubscriptNode.java
index 43486bf76a3b037d6e5eaf5ab11043ceba180ece..6aa4578656348d2c47e4ea9f19d82418716a06af 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubscriptNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubscriptNode.java
@@ -22,9 +22,11 @@
  */
 package com.oracle.truffle.r.nodes.access.vector;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.vector.PositionsCheckNode.PositionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -61,7 +63,8 @@ abstract class PositionCheckSubscriptNode extends PositionCheckNode {
     }
 
     @Specialization
-    protected RAbstractVector doLogical(PositionProfile statistics, int dimSize, RAbstractLogicalVector position, int positionLength) {
+    protected RAbstractVector doLogical(PositionProfile statistics, int dimSize, RAbstractLogicalVector position, int positionLength,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
         positionNACheck.enable(position);
         byte value = position.getDataAt(0);
         if (positionLength != 1) {
@@ -77,11 +80,12 @@ abstract class PositionCheckSubscriptNode extends PositionCheckNode {
             }
         }
 
-        return doIntegerImpl(statistics, dimSize, positionNACheck.convertLogicalToInt(value), position);
+        return doIntegerImpl(statistics, dimSize, positionNACheck.convertLogicalToInt(value), position, getNamesNode);
     }
 
     @Specialization
-    protected RAbstractVector doInteger(PositionProfile profile, int dimSize, RAbstractIntVector position, int positionLength) {
+    protected RAbstractVector doInteger(PositionProfile profile, int dimSize, RAbstractIntVector position, int positionLength,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
         if (positionLength != 1) {
             error.enter();
             Message message;
@@ -99,12 +103,12 @@ abstract class PositionCheckSubscriptNode extends PositionCheckNode {
         }
         assert positionLength == 1;
         positionNACheck.enable(position);
-        RAbstractVector result = doIntegerImpl(profile, dimSize, position.getDataAt(0), position);
+        RAbstractVector result = doIntegerImpl(profile, dimSize, position.getDataAt(0), position, getNamesNode);
         return result;
 
     }
 
-    private RAbstractVector doIntegerImpl(PositionProfile profile, int dimSize, int value, RAbstractVector originalVector) {
+    private RAbstractVector doIntegerImpl(PositionProfile profile, int dimSize, int value, RAbstractVector originalVector, GetNamesAttributeNode getNamesNode) {
         int result;
         if (greaterZero.profile(value > 0)) {
             // fast path
@@ -121,7 +125,7 @@ abstract class PositionCheckSubscriptNode extends PositionCheckNode {
         }
         profile.selectedPositionsCount = 1;
 
-        RStringVector names = originalVector.getNames(attributeProfile);
+        RStringVector names = getNamesNode.getNames(originalVector);
         if (names != null) {
             return RDataFactory.createIntVector(new int[]{result}, !profile.containsNA, names);
         } else {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java
index bc29b18d2a136d3ebb10508126a66727b3b771a0..99ad2b78cab1e9f3630e33e9a8c1345da56e6735 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java
@@ -31,12 +31,13 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.access.vector.PositionsCheckNode.PositionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
 import com.oracle.truffle.r.runtime.NullProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RMissing;
@@ -128,8 +129,6 @@ abstract class PositionCheckSubsetNode extends PositionCheckNode {
         return position;
     }
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
     @Specialization(/* contains = "doSequence" */)
     protected RAbstractVector doDouble(PositionProfile profile, int dimensionLength, RAbstractDoubleVector position, int positionLength, //
                     @Cached("create()") BranchProfile seenZeroProfile, //
@@ -137,13 +136,15 @@ abstract class PositionCheckSubsetNode extends PositionCheckNode {
                     @Cached("create()") BranchProfile seenNegativeProfile, //
                     @Cached("create()") BranchProfile seenOutOfBounds, //
                     @Cached("create()") NullProfile hasNamesProfile, //
-                    @Cached("createCountingProfile()") LoopConditionProfile lengthProfile) {
+                    @Cached("createCountingProfile()") LoopConditionProfile lengthProfile,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode,
+                    @Cached("create()") SetNamesAttributeNode setNamesNode) {
         RAbstractIntVector intPosition = RDataFactory.createIntVector(positionLength);
         intPosition.setComplete(position.isComplete());
         // requires names preservation
-        RStringVector names = hasNamesProfile.profile(position.getNames(attrProfiles));
+        RStringVector names = hasNamesProfile.profile(getNamesNode.getNames(position));
         if (names != null) {
-            intPosition.setNames(names);
+            setNamesNode.setNames(intPosition, names);
         }
         Object convertedStore = intPosition.getInternalStore();
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java
index e1f30141ef54d7abc96f2dc4f0f5a5133c81f677..78faca3c4d6bfe0b214b34a5ee689421b0ccad47 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java
@@ -28,8 +28,11 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -47,8 +50,9 @@ public abstract class CopyAttributesNode extends RBaseNode {
 
     private final boolean copyAllAttributes;
 
-    protected final RAttributeProfiles attrLeftProfiles = RAttributeProfiles.create();
-    protected final RAttributeProfiles attrRightProfiles = RAttributeProfiles.create();
+    @Child protected HasFixedAttributeNode hasDimNode = HasFixedAttributeNode.createDim();
+    @Child protected GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
+    @Child protected GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     protected CopyAttributesNode(boolean copyAllAttributes) {
         this.copyAllAttributes = copyAllAttributes;
@@ -60,9 +64,9 @@ public abstract class CopyAttributesNode extends RBaseNode {
 
     public abstract RAbstractVector execute(RAbstractVector target, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength);
 
-    protected boolean containsMetadata(RAbstractVector vector, RAttributeProfiles attrProfiles) {
-        return vector instanceof RVector && vector.hasDimensions() || (copyAllAttributes && vector.getAttributes() != null) || vector.getDimNames(attrProfiles) != null ||
-                        vector.getNames(attrProfiles) != null;
+    protected boolean containsMetadata(RAbstractVector vector) {
+        return vector instanceof RVector && hasDimNode.execute(vector) || (copyAllAttributes && vector.getAttributes() != null) || getDimNamesNode.getDimNames(vector) != null ||
+                        getNamesNode.getNames(vector) != null;
     }
 
     private static int countNo;
@@ -98,7 +102,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
     }
 
     @SuppressWarnings("unused")
-    @Specialization(guards = {"!containsMetadata(left, attrLeftProfiles)", "!containsMetadata(right, attrRightProfiles)"})
+    @Specialization(guards = {"!containsMetadata(left)", "!containsMetadata(right)"})
     protected RAbstractVector copyNoMetadata(RAbstractVector target, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength) {
         if (LOG) {
             log("copyAttributes: no");
@@ -107,7 +111,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
         return target;
     }
 
-    @Specialization(guards = {"leftLength == rightLength", "containsMetadata(left, attrLeftProfiles) || containsMetadata(right, attrRightProfiles)"})
+    @Specialization(guards = {"leftLength == rightLength", "containsMetadata(left) || containsMetadata(right)"})
     protected RAbstractVector copySameLength(RAbstractVector target, RAbstractVector left, @SuppressWarnings("unused") int leftLength, RAbstractVector right,
                     @SuppressWarnings("unused") int rightLength,
                     @Cached("create()") CopyOfRegAttributesNode copyOfRegLeft,
@@ -124,7 +128,10 @@ public abstract class CopyAttributesNode extends RBaseNode {
                     @Cached("create()") BranchProfile noDimensions,
                     @Cached("createBinaryProfile()") ConditionProfile hasNamesLeft,
                     @Cached("createBinaryProfile()") ConditionProfile hasNamesRight,
-                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
+                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames,
+                    @Cached("create()") GetDimAttributeNode getLeftDimsNode,
+                    @Cached("create()") GetDimAttributeNode getRightDimsNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
         if (LOG) {
             log("copyAttributes: ==");
             countEquals++;
@@ -139,32 +146,28 @@ public abstract class CopyAttributesNode extends RBaseNode {
             }
         }
 
-        int[] newDimensions = left.getDimensions();
+        int[] newDimensions = getLeftDimsNode.getDimensions(left);
         if (newDimensions == null) {
-            newDimensions = right.getDimensions();
+            newDimensions = getRightDimsNode.getDimensions(right);
             if (newDimensions == null) {
                 noDimensions.enter();
                 DynamicObject attributes = result.getAttributes();
                 if (hasAttributes.profile(attributes != null)) {
                     removeDim.execute(attributes);
                     removeDimNames.execute(attributes);
-                    result.setInternalDimNames(null);
                 }
-                result.setInternalDimensions(null);
 
-                RStringVector vecNames = left.getNames(attrLeftProfiles);
+                RStringVector vecNames = getNamesNode.getNames(left);
                 if (hasNamesLeft.profile(vecNames != null)) {
                     if (result != left) {
                         putNames.execute(initAttributes.execute(result), vecNames);
-                        result.setInternalNames(vecNames);
                     }
                     return result;
                 }
                 if (result != right) {
-                    vecNames = right.getNames(attrRightProfiles);
+                    vecNames = getNamesNode.getNames(right);
                     if (hasNamesRight.profile(vecNames != null)) {
                         putNames.execute(initAttributes.execute(result), vecNames);
-                        result.setInternalNames(vecNames);
                     }
                 }
                 return result;
@@ -176,28 +179,26 @@ public abstract class CopyAttributesNode extends RBaseNode {
         }
 
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
 
         if (result != left) {
-            RList newDimNames = left.getDimNames(attrLeftProfiles);
+            RList newDimNames = getDimNamesNode.getDimNames(left);
             if (hasDimNames.profile(newDimNames != null)) {
                 putDimNames.execute(result.getAttributes(), newDimNames);
 
                 newDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
-                result.setInternalDimNames(newDimNames);
                 return result;
             }
             if (result != right) {
-                newDimNames = right.getDimNames(attrRightProfiles);
+                newDimNames = getDimNamesNode.getDimNames(right);
                 if (hasDimNames.profile(newDimNames != null)) {
-                    result.setDimNames(newDimNames);
+                    setDimNamesNode.setDimNames(result, newDimNames);
                 }
             }
         }
         return result;
     }
 
-    @Specialization(guards = {"leftLength < rightLength", "containsMetadata(left, attrLeftProfiles) || containsMetadata(right, attrRightProfiles)"})
+    @Specialization(guards = {"leftLength < rightLength", "containsMetadata(left) || containsMetadata(right)"})
     protected RAbstractVector copyShorter(RAbstractVector target, RAbstractVector left, @SuppressWarnings("unused") int leftLength, RAbstractVector right, @SuppressWarnings("unused") int rightLength, //
                     @Cached("create()") CopyOfRegAttributesNode copyOfReg, //
                     @Cached("createBinaryProfile()") ConditionProfile rightNotResultProfile, //
@@ -208,7 +209,10 @@ public abstract class CopyAttributesNode extends RBaseNode {
                     @Cached("createDim()") SetFixedAttributeNode putDim, //
                     @Cached("create()") InitAttributesNode initAttributes, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNames, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
+                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames,
+                    @Cached("create()") GetDimAttributeNode getLeftDimsNode,
+                    @Cached("create()") GetDimAttributeNode getRightDimsNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
         if (LOG) {
             log("copyAttributes: <");
             countSmaller++;
@@ -219,18 +223,17 @@ public abstract class CopyAttributesNode extends RBaseNode {
             copyOfReg.execute(right, result);
         }
 
-        int[] newDimensions = left.getDimensions();
+        int[] newDimensions = getLeftDimsNode.getDimensions(left);
         if (newDimensions == null || (newDimensions.length == 2 && newDimensions[0] == 1 && newDimensions[1] == 1)) {
             // 1-element matrix should be treated as 1-element vector
-            newDimensions = right.getDimensions();
+            newDimensions = getRightDimsNode.getDimensions(right);
             if (newDimensions == null || (newDimensions.length == 2 && newDimensions[0] == 1 && newDimensions[1] == 1)) {
                 // 1-element matrix should be treated as 1-element vector
                 noDimensions.enter();
                 if (rightNotResult) {
-                    RStringVector vecNames = right.getNames(attrRightProfiles);
+                    RStringVector vecNames = getNamesNode.getNames(right);
                     if (hasNames.profile(vecNames != null)) {
                         putNames.execute(initAttributes.execute(result), vecNames);
-                        result.setInternalNames(vecNames);
                     }
                 }
                 return result;
@@ -243,17 +246,16 @@ public abstract class CopyAttributesNode extends RBaseNode {
 
         RVector.verifyDimensions(result.getLength(), newDimensions, this);
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
         if (rightNotResult) {
-            RList newDimNames = right.getDimNames(attrRightProfiles);
+            RList newDimNames = getDimNamesNode.getDimNames(right);
             if (hasDimNames.profile(newDimNames != null)) {
-                result.setDimNames(newDimNames);
+                setDimNamesNode.setDimNames(result, newDimNames);
             }
         }
         return result;
     }
 
-    @Specialization(guards = {"leftLength > rightLength", "containsMetadata(left, attrLeftProfiles) || containsMetadata(right, attrRightProfiles)"})
+    @Specialization(guards = {"leftLength > rightLength", "containsMetadata(left) || containsMetadata(right)"})
     protected RAbstractVector copyLonger(RAbstractVector target, RAbstractVector left, @SuppressWarnings("unused") int leftLength, RAbstractVector right, @SuppressWarnings("unused") int rightLength, //
                     @Cached("create()") CopyOfRegAttributesNode copyOfReg, //
                     @Cached("create()") BranchProfile leftHasDimensions, //
@@ -263,7 +265,10 @@ public abstract class CopyAttributesNode extends RBaseNode {
                     @Cached("createDim()") SetFixedAttributeNode putDim, //
                     @Cached("create()") InitAttributesNode initAttributes, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNames, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
+                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames,
+                    @Cached("create()") GetDimAttributeNode getLeftDimsNode,
+                    @Cached("create()") GetDimAttributeNode getRightDimsNode,
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
         if (LOG) {
             log("copyAttributes: >");
             countLarger++;
@@ -272,16 +277,15 @@ public abstract class CopyAttributesNode extends RBaseNode {
         if (copyAllAttributes && result != left) {
             copyOfReg.execute(left, result);
         }
-        int[] newDimensions = left.getDimensions();
+        int[] newDimensions = getLeftDimsNode.getDimensions(left);
         if (newDimensions == null) {
-            newDimensions = right.getDimensions();
+            newDimensions = getRightDimsNode.getDimensions(right);
             if (newDimensions == null) {
                 noDimensions.enter();
                 if (left != result) {
-                    RStringVector vecNames = left.getNames(attrLeftProfiles);
+                    RStringVector vecNames = getNamesNode.getNames(left);
                     if (hasNames.profile(vecNames != null)) {
                         putNames.execute(initAttributes.execute(result), vecNames);
-                        result.setInternalNames(vecNames);
                     }
                 }
                 return result;
@@ -292,11 +296,10 @@ public abstract class CopyAttributesNode extends RBaseNode {
             leftHasDimensions.enter();
         }
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
         if (left != result) {
-            RList newDimNames = left.getDimNames(attrLeftProfiles);
+            RList newDimNames = getDimNamesNode.getDimNames(left);
             if (hasDimNames.profile(newDimNames != null)) {
-                result.setDimNames(newDimNames);
+                setDimNamesNode.setDimNames(result, newDimNames);
             }
         }
         return result;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java
index 7b6897b18b8ecdd0cc42a7c8aff3085a9b3c0a1e..d1422eebc32fb87cfcdb041b1b411aae9a1a2c35 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
-import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.Property;
@@ -30,7 +29,6 @@ import com.oracle.truffle.api.object.Shape;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
@@ -112,20 +110,14 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
     protected void copyGeneric(RAbstractVector source, RVector<?> target) {
         DynamicObject orgAttributes = source.getAttributes();
         if (orgAttributes != null) {
-            Object newRowNames = null;
-
             Shape shape = orgAttributes.getShape();
             for (Property p : shape.getProperties()) {
                 String name = (String) p.getKey();
                 if (name != RRuntime.DIM_ATTR_KEY && name != RRuntime.DIMNAMES_ATTR_KEY && name != RRuntime.NAMES_ATTR_KEY) {
                     Object val = p.get(orgAttributes, shape);
                     target.initAttributes().define(name, val);
-                    if (name == RRuntime.ROWNAMES_ATTR_KEY) {
-                        newRowNames = val;
-                    }
                 }
             }
-            target.setInternalRowNames(newRowNames == null ? RNull.instance : newRowNames);
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java
index 0a28d002af32b82684ecf48e4f815256e363c859..858530667ff7dc7246205f084dd710e3e0b2d631 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java
@@ -22,16 +22,29 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 
+/**
+ * This node is responsible for retrieving a value from an arbitrary attribute. It accepts both
+ * {@link DynamicObject} and {@link RAttributable} instances as the first argument. If the first
+ * argument is {@link RAttributable} and its attributes are initialized, the recursive instance of
+ * this class is used to get the attribute value from the attributes.
+ */
 public abstract class GetAttributeNode extends AttributeAccessNode {
 
+    @Child private GetAttributeNode recursive;
+
     protected GetAttributeNode() {
     }
 
@@ -39,7 +52,7 @@ public abstract class GetAttributeNode extends AttributeAccessNode {
         return GetAttributeNodeGen.create();
     }
 
-    public abstract Object execute(DynamicObject attrs, String name);
+    public abstract Object execute(Object attrs, String name);
 
     @Specialization(limit = "3", //
                     guards = {"cachedName.equals(name)", "shapeCheck(shape, attrs)"}, //
@@ -58,4 +71,30 @@ public abstract class GetAttributeNode extends AttributeAccessNode {
         return attrs.get(name);
     }
 
+    @Specialization
+    protected Object getAttrFromAttributable(RAttributable x, String name,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return null;
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create());
+        }
+
+        return recursive.execute(attributes, name);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
index 35b79c0d788b2e5f0ac8b45900b880778437d283..5b1b1963faebb517b9f6156dad202f17cfa632b8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
@@ -22,38 +22,57 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 
+/**
+ * This node is responsible for retrieving a value from the predefined (fixed) attribute. It accepts
+ * both {@link DynamicObject} and {@link RAttributable} instances as the first argument. If the
+ * first argument is {@link RAttributable} and its attributes are initialized, the recursive
+ * instance of this class is used to get the attribute value from the attributes.
+ */
 public abstract class GetFixedAttributeNode extends FixedAttributeAccessNode {
 
+    @Child private GetFixedAttributeNode recursive;
+
     protected GetFixedAttributeNode(String name) {
         super(name);
     }
 
     public static GetFixedAttributeNode create(String name) {
-        return GetFixedAttributeNodeGen.create(name);
+        if (SpecialAttributesFunctions.IsSpecialAttributeNode.isSpecialAttribute(name)) {
+            return SpecialAttributesFunctions.createGetSpecialAttributeNode(name);
+        } else {
+            return GetFixedAttributeNodeGen.create(name);
+        }
     }
 
     public static GetFixedAttributeNode createNames() {
-        return GetFixedAttributeNode.create(RRuntime.NAMES_ATTR_KEY);
+        return GetNamesAttributeNode.create();
     }
 
-    public static GetFixedAttributeNode createDim() {
-        return GetFixedAttributeNode.create(RRuntime.DIM_ATTR_KEY);
+    public static GetDimAttributeNode createDim() {
+        return GetDimAttributeNode.create();
     }
 
-    public static GetFixedAttributeNode createClass() {
-        return GetFixedAttributeNode.create(RRuntime.CLASS_ATTR_KEY);
+    public static GetClassAttributeNode createClass() {
+        return GetClassAttributeNode.create();
     }
 
-    public abstract Object execute(DynamicObject attrs);
+    public abstract Object execute(Object attr);
 
     protected boolean hasProperty(Shape shape) {
         return shape.hasProperty(name);
@@ -74,4 +93,31 @@ public abstract class GetFixedAttributeNode extends FixedAttributeAccessNode {
     protected Object getAttrFallback(DynamicObject attrs) {
         return attrs.get(name);
     }
+
+    @Specialization
+    protected Object getAttrFromAttributable(RAttributable x,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return null;
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create(name));
+        }
+
+        return recursive.execute(attributes);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/HasFixedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/HasFixedAttributeNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..fdff7b2c0f7c3418a2847f03020d043e0473e74f
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/HasFixedAttributeNode.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.attributes;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.api.object.Location;
+import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributeStorage;
+
+/**
+ * This node is responsible for determining the existence of the predefined (fixed) attribute. It
+ * accepts both {@link DynamicObject} and {@link RAttributable} instances as the first argument. If
+ * the first argument is {@link RAttributable} and its attributes are initialized, the recursive
+ * instance of this class is used to determine the existence from the attributes.
+ */
+public abstract class HasFixedAttributeNode extends FixedAttributeAccessNode {
+
+    @Child private HasFixedAttributeNode recursive;
+
+    protected HasFixedAttributeNode(String name) {
+        super(name);
+    }
+
+    public static HasFixedAttributeNode create(String name) {
+        return HasFixedAttributeNodeGen.create(name);
+    }
+
+    public static HasFixedAttributeNode createDim() {
+        return HasFixedAttributeNodeGen.create(RRuntime.DIM_ATTR_KEY);
+    }
+
+    public abstract boolean execute(Object attr);
+
+    protected boolean hasProperty(Shape shape) {
+        return shape.hasProperty(name);
+    }
+
+    @Specialization(limit = "3", //
+                    guards = {"shapeCheck(shape, attrs)"}, //
+                    assumptions = {"shape.getValidAssumption()"})
+    @SuppressWarnings("unused")
+    protected boolean hasAttrCached(DynamicObject attrs,
+                    @Cached("lookupShape(attrs)") Shape shape,
+                    @Cached("lookupLocation(shape, name)") Location location) {
+        return location != null;
+    }
+
+    @Specialization(contains = "hasAttrCached")
+    @TruffleBoundary
+    protected boolean hasAttrFallback(DynamicObject attrs) {
+        return attrs.containsKey(name);
+    }
+
+    @Specialization
+    protected boolean hasAttrFromAttributable(RAttributable x,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return false;
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create(name));
+        }
+
+        return recursive.execute(attributes);
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java
index 5d41dae1dbc3861f24152719abd03b86707050e0..b9c737057e670e1ed1d3938bbedabf588c48c737 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java
@@ -26,10 +26,17 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
-import com.oracle.truffle.api.object.Property;
+import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.RemoveClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.RemoveDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.RemoveDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.RemoveNamesAttributeNode;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 
 public abstract class RemoveFixedAttributeNode extends FixedAttributeAccessNode {
 
@@ -38,42 +45,64 @@ public abstract class RemoveFixedAttributeNode extends FixedAttributeAccessNode
     }
 
     public static RemoveFixedAttributeNode create(String name) {
-        return RemoveFixedAttributeNodeGen.create(name);
+        if (SpecialAttributesFunctions.IsSpecialAttributeNode.isSpecialAttribute(name)) {
+            return SpecialAttributesFunctions.createRemoveSpecialAttributeNode(name);
+        } else {
+            return RemoveFixedAttributeNodeGen.create(name);
+        }
     }
 
     public static RemoveFixedAttributeNode createNames() {
-        return RemoveFixedAttributeNode.create(RRuntime.NAMES_ATTR_KEY);
+        return RemoveNamesAttributeNode.create();
     }
 
     public static RemoveFixedAttributeNode createDim() {
-        return RemoveFixedAttributeNode.create(RRuntime.DIM_ATTR_KEY);
+        return RemoveDimAttributeNode.create();
     }
 
     public static RemoveFixedAttributeNode createDimNames() {
-        return RemoveFixedAttributeNode.create(RRuntime.DIMNAMES_ATTR_KEY);
+        return RemoveDimNamesAttributeNode.create();
     }
 
     public static RemoveFixedAttributeNode createClass() {
-        return RemoveFixedAttributeNode.create(RRuntime.CLASS_ATTR_KEY);
+        return RemoveClassAttributeNode.create();
     }
 
-    public abstract void execute(DynamicObject attrs);
+    public abstract void execute(Object attrs);
 
     @Specialization(limit = "3", //
-                    guards = {"shapeCheck(shape, attrs)"}, //
+                    guards = {"shapeCheck(shape, attrs)", "location == null"}, //
                     assumptions = {"shape.getValidAssumption()"})
-    protected void removeAttrCached(DynamicObject attrs,
-                    @Cached("lookupShape(attrs)") Shape shape,
-                    @Cached("lookupProperty(shape, name)") Property property) {
-        if (property != null) {
-            Shape newShape = attrs.getShape().removeProperty(property);
-            attrs.setShapeAndResize(shape, newShape);
-        }
+    protected void removeNonExistantAttr(@SuppressWarnings("unused") DynamicObject attrs,
+                    @SuppressWarnings("unused") @Cached("lookupShape(attrs)") Shape shape,
+                    @SuppressWarnings("unused") @Cached("lookupLocation(shape, name)") Location location) {
+        // do nothing
     }
 
-    @Specialization(contains = "removeAttrCached")
+    @Specialization
     @TruffleBoundary
     protected void removeAttrFallback(DynamicObject attrs) {
         attrs.delete(this.name);
     }
+
+    @Specialization
+    protected void removeAttrFromAttributable(RAttributable x,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return;
+        }
+
+        removeAttrFallback(attributes);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java
index b669fa8b59fdef3af23f82a6455888e6c742d45e..aecd9e3c0fc95b1f2f6cdb3c2bb80e3c5ff862da 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -30,10 +31,27 @@ import com.oracle.truffle.api.object.FinalLocationException;
 import com.oracle.truffle.api.object.IncompatibleLocationException;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 
+/**
+ * This node is responsible for setting a value to an arbitrary attribute. It accepts both
+ * {@link DynamicObject} and {@link RAttributable} instances as the first argument. If the first
+ * argument is {@link RAttributable} and the attribute is a special one (i.e. names, dims, dimnames,
+ * rownames), a corresponding node defined in the {@link SpecialAttributesFunctions} class is
+ * created and the processing is delegated to it. If the first argument is {@link RAttributable} and
+ * the attribute is not a special one, it is made sure that the attributes in the first argument are
+ * initialized. Then the recursive instance of this class is used to set the attribute value to the
+ * attributes.
+ */
 public abstract class SetAttributeNode extends AttributeAccessNode {
 
+    @Child SetAttributeNode recursive;
+
     protected SetAttributeNode() {
     }
 
@@ -41,7 +59,7 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
         return SetAttributeNodeGen.create();
     }
 
-    public abstract void execute(DynamicObject attrs, String name, Object value);
+    public abstract void execute(Object attrs, String name, Object value);
 
     @Specialization(limit = "3", //
                     guards = {
@@ -100,6 +118,57 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
         receiver.define(name, value);
     }
 
+    protected static SpecialAttributesFunctions.SetSpecialAttributeNode createSpecAttrNode(String name) {
+        return SpecialAttributesFunctions.createSetSpecialAttributeNode(name);
+    }
+
+    @Specialization(limit = "3", //
+                    guards = {
+                                    "isSpecialAttributeNode.execute(name)",
+                                    "cachedName.equals(name)"
+                    })
+    @SuppressWarnings("unused")
+    protected void setSpecAttrInAttributable(RAttributable x, String name, Object value,
+                    @Cached("create()") SpecialAttributesFunctions.IsSpecialAttributeNode isSpecialAttributeNode,
+                    @Cached("name") String cachedName,
+                    @Cached("createSpecAttrNode(cachedName)") SpecialAttributesFunctions.SetSpecialAttributeNode setSpecAttrNode) {
+        setSpecAttrNode.execute(x, value);
+    }
+
+    @Specialization(contains = "setSpecAttrInAttributable", //
+                    guards = "isSpecialAttributeNode.execute(name)")
+    @SuppressWarnings("unused")
+    protected void setSpecAttrInAttributable(RAttributable x, String name, Object value,
+                    @Cached("create()") SpecialAttributesFunctions.IsSpecialAttributeNode isSpecialAttributeNode,
+                    @Cached("create()") SpecialAttributesFunctions.GenericSpecialAttributeNode genericSpecialAttrNode) {
+        genericSpecialAttrNode.execute(x, name, value);
+    }
+
+    @Specialization
+    protected void setAttrInAttributable(RAttributable x, String name, Object value,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            attributes = x.initAttributes();
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create());
+        }
+
+        recursive.execute(attributes, name, value);
+    }
+
     /**
      * Try to find the given property in the shape. Also returns null when the value cannot be store
      * into the location.
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java
index 3f6b8b6bebd444f5cc1fd567b60b71d6cda3b159..fd79ede63e6e57041d801f7eecbd7355ca1f50e6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -30,36 +31,58 @@ import com.oracle.truffle.api.object.FinalLocationException;
 import com.oracle.truffle.api.object.IncompatibleLocationException;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetSpecialAttributeNode;
 import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 
+/**
+ * This node is responsible for setting a value to the predefined (fixed) attribute. It accepts both
+ * {@link DynamicObject} and {@link RAttributable} instances as the first argument. If the first
+ * argument is {@link RAttributable} and the attribute is a special one (i.e. names, dims, dimnames,
+ * rownames), a corresponding node defined in the {@link SpecialAttributesFunctions} class is
+ * created and the processing is delegated to it. If the first argument is {@link RAttributable} and
+ * the attribute is not a special one, it is made sure that the attributes in the first argument are
+ * initialized. Then the recursive instance of this class is used to set the attribute value to the
+ * attributes.
+ */
 public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
 
+    @Child private SetFixedAttributeNode recursive;
+    @Child private SetSpecialAttributeNode setSpecialAttrNode;
+
     protected SetFixedAttributeNode(String name) {
         super(name);
     }
 
     public static SetFixedAttributeNode create(String name) {
-        return SetFixedAttributeNodeGen.create(name);
+        if (SpecialAttributesFunctions.IsSpecialAttributeNode.isSpecialAttribute(name)) {
+            return SpecialAttributesFunctions.createSetSpecialAttributeNode(name);
+        } else {
+            return SetFixedAttributeNodeGen.create(name);
+        }
     }
 
     public static SetFixedAttributeNode createNames() {
-        return SetFixedAttributeNode.create(RRuntime.NAMES_ATTR_KEY);
+        return SpecialAttributesFunctions.SetNamesAttributeNode.create();
     }
 
     public static SetFixedAttributeNode createDim() {
-        return SetFixedAttributeNode.create(RRuntime.DIM_ATTR_KEY);
+        return SpecialAttributesFunctions.SetDimAttributeNode.create();
     }
 
     public static SetFixedAttributeNode createDimNames() {
-        return SetFixedAttributeNode.create(RRuntime.DIMNAMES_ATTR_KEY);
+        return SpecialAttributesFunctions.SetDimNamesAttributeNode.create();
     }
 
     public static SetFixedAttributeNode createClass() {
-        return SetFixedAttributeNode.create(RRuntime.CLASS_ATTR_KEY);
+        return SpecialAttributesFunctions.SetClassAttributeNode.create();
     }
 
-    public abstract void execute(DynamicObject attrs, Object value);
+    public abstract void execute(Object attr, Object value);
 
     @Specialization(limit = "3", //
                     guards = {"shapeCheck(shape, attrs)", "location != null"}, //
@@ -74,10 +97,54 @@ public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
         }
     }
 
+    @Specialization(limit = "3", //
+                    guards = {"shapeCheck(oldShape, attrs)", "oldLocation == null"}, //
+                    assumptions = {"oldShape.getValidAssumption()", "newShape.getValidAssumption()"})
+    protected static void setNewAttrCached(DynamicObject attrs, Object value,
+                    @Cached("lookupShape(attrs)") Shape oldShape,
+                    @SuppressWarnings("unused") @Cached("lookupLocation(oldShape, name)") Location oldLocation,
+                    @Cached("defineProperty(oldShape, name, value)") Shape newShape,
+                    @Cached("lookupLocation(newShape, name)") Location newLocation) {
+        try {
+            newLocation.set(attrs, value, oldShape, newShape);
+        } catch (IncompatibleLocationException ex) {
+            RInternalError.reportError(ex);
+        }
+    }
+
+    protected static Shape defineProperty(Shape oldShape, Object name, Object value) {
+        return oldShape.defineProperty(name, value, 0);
+    }
+
     @Specialization(contains = "setAttrCached")
     @TruffleBoundary
     protected void setFallback(DynamicObject attrs, Object value) {
         attrs.define(name, value);
     }
 
+    @Specialization
+    protected void setAttrInAttributable(RAttributable x, Object value,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            attributes = x.initAttributes();
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create(name));
+        }
+
+        recursive.execute(attributes, value);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..e596ca4f5b734b8f433cb47a4b912ab49de67e0a
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java
@@ -0,0 +1,1045 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.attributes;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.LoopConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.GetDimAttributeNodeGen;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RInteger;
+import com.oracle.truffle.r.runtime.data.RLanguage;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RScalarVector;
+import com.oracle.truffle.r.runtime.data.RSequence;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+
+/**
+ * This class defines a number of nodes used to handle the special attributes, such as names, dims,
+ * dimnames and rownames.
+ */
+public final class SpecialAttributesFunctions {
+
+    /**
+     * A node used in guards, for example, to determine whether an attribute is a special one.
+     */
+    public static final class IsSpecialAttributeNode extends RBaseNode {
+
+        private final BranchProfile namesProfile = BranchProfile.create();
+        private final BranchProfile dimProfile = BranchProfile.create();
+        private final BranchProfile dimNamesProfile = BranchProfile.create();
+        private final BranchProfile rowNamesProfile = BranchProfile.create();
+        private final BranchProfile classProfile = BranchProfile.create();
+
+        public static IsSpecialAttributeNode create() {
+            return new IsSpecialAttributeNode();
+        }
+
+        /**
+         * The fast-path method.
+         */
+        public boolean execute(String name) {
+            assert name.intern() == name;
+            if (name == RRuntime.NAMES_ATTR_KEY) {
+                namesProfile.enter();
+                return true;
+            } else if (name == RRuntime.DIM_ATTR_KEY) {
+                dimProfile.enter();
+                return true;
+            } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+                dimNamesProfile.enter();
+                return true;
+            } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+                rowNamesProfile.enter();
+                return true;
+            } else if (name == RRuntime.CLASS_ATTR_KEY) {
+                classProfile.enter();
+                return false;
+            }
+            return false;
+        }
+
+        /**
+         * The slow-path method.
+         */
+        public static boolean isSpecialAttribute(String name) {
+            assert name.intern() == name;
+            return name == RRuntime.NAMES_ATTR_KEY ||
+                            name == RRuntime.DIM_ATTR_KEY ||
+                            name == RRuntime.DIMNAMES_ATTR_KEY ||
+                            name == RRuntime.ROWNAMES_ATTR_KEY ||
+                            name == RRuntime.CLASS_ATTR_KEY;
+
+        }
+    }
+
+    /**
+     * A node for setting a value to any special attribute.
+     */
+    public static final class GenericSpecialAttributeNode extends RBaseNode {
+
+        private final BranchProfile namesProfile = BranchProfile.create();
+        private final BranchProfile dimProfile = BranchProfile.create();
+        private final BranchProfile dimNamesProfile = BranchProfile.create();
+        private final BranchProfile rowNamesProfile = BranchProfile.create();
+
+        @Child private SetNamesAttributeNode namesAttrNode;
+        @Child private SetDimAttributeNode dimAttrNode;
+        @Child private SetDimNamesAttributeNode dimNamesAttrNode;
+        @Child private SetRowNamesAttributeNode rowNamesAttrNode;
+
+        public static GenericSpecialAttributeNode create() {
+            return new GenericSpecialAttributeNode();
+        }
+
+        public void execute(RAttributable x, String name, Object value) {
+            assert name.intern() == name;
+            if (name == RRuntime.NAMES_ATTR_KEY) {
+                namesProfile.enter();
+                if (namesAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    namesAttrNode = insert(SetNamesAttributeNode.create());
+                }
+                namesAttrNode.execute(x, value);
+            } else if (name == RRuntime.DIM_ATTR_KEY) {
+                dimProfile.enter();
+                if (dimAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    dimAttrNode = insert(SetDimAttributeNode.create());
+                }
+                dimAttrNode.execute(x, value);
+            } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+                dimNamesProfile.enter();
+                if (dimNamesAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    dimNamesAttrNode = insert(SetDimNamesAttributeNode.create());
+                }
+                dimNamesAttrNode.execute(x, value);
+            } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+                rowNamesProfile.enter();
+                if (rowNamesAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    rowNamesAttrNode = insert(SetRowNamesAttributeNode.create());
+                }
+                rowNamesAttrNode.execute(x, value);
+            } else if (name == RRuntime.CLASS_ATTR_KEY) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                throw RInternalError.unimplemented("The \"class\" attribute should be set using a separate method");
+            } else {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                throw RInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    /**
+     * A factory method for creating a node setting the given special attribute.
+     *
+     * @param name the special attribute name
+     * @return the node
+     */
+    public static SetSpecialAttributeNode createSetSpecialAttributeNode(String name) {
+        assert name.intern() == name;
+        if (name == RRuntime.NAMES_ATTR_KEY) {
+            return SetNamesAttributeNode.create();
+        } else if (name == RRuntime.DIM_ATTR_KEY) {
+            return SetDimAttributeNode.create();
+        } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+            return SetDimNamesAttributeNode.create();
+        } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+            return SetRowNamesAttributeNode.create();
+        } else if (name == RRuntime.CLASS_ATTR_KEY) {
+            return SetClassAttributeNode.create();
+        } else {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * A factory method for creating a node removing the given special attribute.
+     *
+     * @param name the special attribute name
+     * @return the node
+     */
+    public static RemoveSpecialAttributeNode createRemoveSpecialAttributeNode(String name) {
+        assert name.intern() == name;
+        if (name == RRuntime.NAMES_ATTR_KEY) {
+            return RemoveNamesAttributeNode.create();
+        } else if (name == RRuntime.DIM_ATTR_KEY) {
+            return RemoveDimAttributeNode.create();
+        } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+            return RemoveDimNamesAttributeNode.create();
+        } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+            return RemoveRowNamesAttributeNode.create();
+        } else if (name == RRuntime.CLASS_ATTR_KEY) {
+            return RemoveClassAttributeNode.create();
+        } else {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * A factory method for creating a node retrieving the given special attribute.
+     *
+     * @param name the special attribute name
+     * @return the node
+     */
+    public static GetFixedAttributeNode createGetSpecialAttributeNode(String name) {
+        assert name.intern() == name;
+        if (name == RRuntime.NAMES_ATTR_KEY) {
+            return GetNamesAttributeNode.create();
+        } else if (name == RRuntime.DIM_ATTR_KEY) {
+            return GetDimAttributeNode.create();
+        } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+            return GetDimNamesAttributeNode.create();
+        } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+            return GetRowNamesAttributeNode.create();
+        } else if (name == RRuntime.CLASS_ATTR_KEY) {
+            return GetClassAttributeNode.create();
+        } else {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    /**
+     * The base class for the nodes setting values to special attributes.
+     */
+    public abstract static class SetSpecialAttributeNode extends SetFixedAttributeNode {
+
+        protected SetSpecialAttributeNode(String name) {
+            super(name);
+        }
+
+        public abstract void execute(RAttributable x, Object attrValue);
+
+    }
+
+    /**
+     * The base class for the nodes removing values from special attributes.
+     */
+    public abstract static class RemoveSpecialAttributeNode extends RemoveFixedAttributeNode {
+
+        protected RemoveSpecialAttributeNode(String name) {
+            super(name);
+        }
+
+        public abstract void execute(RAttributable x);
+
+        @Specialization(insertBefore = "removeAttrFromAttributable")
+        protected void removeAttrFromVector(RVector<?> x,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("create()") BranchProfile attrEmptyProfile) {
+            DynamicObject attributes = x.getAttributes();
+            if (attributes == null) {
+                attrNullProfile.enter();
+                return;
+            }
+
+            attributes.delete(name);
+
+            if (attributes.isEmpty()) {
+                attrEmptyProfile.enter();
+                x.initAttributes(null);
+            }
+        }
+
+    }
+
+    public abstract static class SetNamesAttributeNode extends SetSpecialAttributeNode {
+
+        private final ConditionProfile nullDimNamesProfile = ConditionProfile.createBinaryProfile();
+
+        protected SetNamesAttributeNode() {
+            super(RRuntime.NAMES_ATTR_KEY);
+        }
+
+        public static SetNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetNamesAttributeNodeGen.create();
+        }
+
+        public void setNames(RAbstractContainer x, RStringVector newNames) {
+            if (nullDimNamesProfile.profile(newNames == null)) {
+                execute(x, RNull.instance);
+            } else {
+                execute(x, newNames);
+            }
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void resetDimNames(RAbstractContainer x, @SuppressWarnings("unused") RNull rnull,
+                        @Cached("create()") RemoveNamesAttributeNode removeNamesAttrNode) {
+            removeNamesAttrNode.execute(x);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setNamesInVector(RVector<?> x, RStringVector newNames,
+                        @Cached("create()") BranchProfile namesTooLongProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile useDimNamesProfile,
+                        @Cached("create()") GetDimAttributeNode getDimNode,
+                        @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            RVector<?> xProfiled = xTypeProfile.profile(x);
+            if (newNames.getLength() > xProfiled.getLength()) {
+                namesTooLongProfile.enter();
+                throw RError.error(this, RError.Message.ATTRIBUTE_VECTOR_SAME_LENGTH, RRuntime.NAMES_ATTR_KEY, newNames.getLength(), xProfiled.getLength());
+            }
+
+            int[] dimensions = getDimNode.getDimensions(x);
+            if (useDimNamesProfile.profile(dimensions != null && dimensions.length == 1)) {
+                // for one dimensional array, "names" is really "dimnames[[1]]" (see R
+                // documentation for "names" function)
+                RList newDimNames = RDataFactory.createList(new Object[]{newNames});
+                newDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
+                setDimNamesNode.setDimNames(xProfiled, newDimNames);
+            } else {
+                assert newNames != xProfiled;
+                DynamicObject attrs = xProfiled.getAttributes();
+                if (attrs == null) {
+                    attrNullProfile.enter();
+                    attrs = RAttributesLayout.createNames(newNames);
+                    xProfiled.initAttributes(attrs);
+                    return;
+                }
+
+                super.setAttrInAttributable(xProfiled, newNames, attrNullProfile, attrStorageProfile, xTypeProfile);
+            }
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setNamesInContainer(RAbstractContainer x, RStringVector newNames,
+                        @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setNames(newNames);
+        }
+    }
+
+    public abstract static class RemoveNamesAttributeNode extends RemoveSpecialAttributeNode {
+
+        protected RemoveNamesAttributeNode() {
+            super(RRuntime.NAMES_ATTR_KEY);
+        }
+
+        @Override
+        @Specialization
+        protected void removeAttrFallback(DynamicObject attrs) {
+            super.removeAttrFallback(attrs);
+        }
+
+        public static RemoveNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.RemoveNamesAttributeNodeGen.create();
+        }
+    }
+
+    public abstract static class GetNamesAttributeNode extends GetFixedAttributeNode {
+
+        protected GetNamesAttributeNode() {
+            super(RRuntime.NAMES_ATTR_KEY);
+        }
+
+        public static GetNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.GetNamesAttributeNodeGen.create();
+        }
+
+        public final RStringVector getNames(Object x) {
+            return (RStringVector) execute(x);
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorNames(RVector<?> x,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") BranchProfile namesNullProfile,
+                        @Cached("create()") BranchProfile dimNamesAvlProfile,
+                        @Cached("create()") GetDimNamesAttributeNode getDimNames) {
+            RStringVector names = (RStringVector) super.getAttrFromAttributable(x, attrNullProfile, attrStorageProfile, xTypeProfile);
+            if (names == null) {
+                namesNullProfile.enter();
+                RList dimNames = getDimNames.getDimNames(x);
+                if (dimNames != null && dimNames.getLength() == 1) {
+                    dimNamesAvlProfile.enter();
+                    return dimNames.getDataAt(0);
+                }
+                return null;
+            }
+
+            return names;
+
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorNames(RAbstractContainer x,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") RAttributeProfiles attrProfiles) {
+            return xTypeProfile.profile(x).getNames(attrProfiles);
+        }
+    }
+
+    public abstract static class SetDimAttributeNode extends SetSpecialAttributeNode {
+
+        private final ConditionProfile nullDimProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile naDimProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile negativeDimProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile dimNotMatchLengthProfile = ConditionProfile.createBinaryProfile();
+        private final ValueProfile contArgClassProfile = ValueProfile.createClassProfile();
+        private final ValueProfile dimArgClassProfile = ValueProfile.createClassProfile();
+        private final LoopConditionProfile verifyLoopProfile = LoopConditionProfile.createCountingProfile();
+
+        protected SetDimAttributeNode() {
+            super(RRuntime.DIM_ATTR_KEY);
+        }
+
+        public static SetDimAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetDimAttributeNodeGen.create();
+        }
+
+        public void setDimensions(RAbstractContainer x, int[] dims) {
+            if (nullDimProfile.profile(dims == null)) {
+                execute(x, RNull.instance);
+            } else {
+                execute(x, RDataFactory.createIntVector(dims, RDataFactory.COMPLETE_VECTOR));
+            }
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void resetDims(RAbstractContainer x, @SuppressWarnings("unused") RNull rnull,
+                        @Cached("create()") RemoveDimAttributeNode removeDimAttrNode,
+                        @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+            removeDimAttrNode.execute(x);
+            setDimNamesNode.setDimNames(x, null);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setOneDimInVector(RVector<?> x, int dim,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            RAbstractContainer xProfiled = contArgClassProfile.profile(x);
+
+            int[] dims = new int[]{dim};
+            verifyOneDimensions(xProfiled.getLength(), dim);
+
+            RIntVector dimVec = RDataFactory.createIntVector(dims, RDataFactory.COMPLETE_VECTOR);
+
+            DynamicObject attrs = xProfiled.getAttributes();
+            if (attrs == null) {
+                attrNullProfile.enter();
+                attrs = RAttributesLayout.createDim(dimVec);
+                xProfiled.initAttributes(attrs);
+                return;
+            }
+
+            super.setAttrInAttributable(x, dimVec, attrNullProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setDimsInVector(RVector<?> x, RAbstractIntVector dims,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            RAbstractContainer xProfiled = contArgClassProfile.profile(x);
+            verifyDimensions(xProfiled.getLength(), dims);
+
+            DynamicObject attrs = xProfiled.getAttributes();
+            if (attrs == null) {
+                attrNullProfile.enter();
+                attrs = RAttributesLayout.createDim(dims);
+                xProfiled.initAttributes(attrs);
+                return;
+            }
+
+            super.setAttrInAttributable(x, dims, attrNullProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setDimsInContainerFallback(RAbstractContainer x, RAbstractIntVector dims,
+                        @Cached("create()") SetDimAttributeNode setDimNode) {
+            int[] dimsArr = dims.materialize().getDataCopy();
+            setDimNode.setDimensions(x, dimsArr);
+        }
+
+        private void verifyOneDimensions(int vectorLength, int dim) {
+            int length = dim;
+            if (naDimProfile.profile(RRuntime.isNA(dim))) {
+                throw RError.error(this, RError.Message.DIMS_CONTAIN_NA);
+            } else if (negativeDimProfile.profile(dim < 0)) {
+                throw RError.error(this, RError.Message.DIMS_CONTAIN_NEGATIVE_VALUES);
+            }
+            if (dimNotMatchLengthProfile.profile(length != vectorLength && vectorLength > 0)) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(this, RError.Message.DIMS_DONT_MATCH_LENGTH, length, vectorLength);
+            }
+        }
+
+        public void verifyDimensions(int vectorLength, RAbstractIntVector dims) {
+            RAbstractIntVector dimsProfiled = dimArgClassProfile.profile(dims);
+            int dimLen = dims.getLength();
+            verifyLoopProfile.profileCounted(dimLen);
+            int length = 1;
+            for (int i = 0; i < dimLen; i++) {
+                int dim = dimsProfiled.getDataAt(i);
+                if (naDimProfile.profile(RRuntime.isNA(dim))) {
+                    CompilerDirectives.transferToInterpreter();
+                    throw RError.error(this, RError.Message.DIMS_CONTAIN_NA);
+                } else if (negativeDimProfile.profile(dim < 0)) {
+                    CompilerDirectives.transferToInterpreter();
+                    throw RError.error(this, RError.Message.DIMS_CONTAIN_NEGATIVE_VALUES);
+                }
+                length *= dim;
+            }
+            if (length != vectorLength && vectorLength > 0) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(this, RError.Message.DIMS_DONT_MATCH_LENGTH, length, vectorLength);
+            }
+        }
+
+    }
+
+    public abstract static class RemoveDimAttributeNode extends RemoveSpecialAttributeNode {
+
+        protected RemoveDimAttributeNode() {
+            super(RRuntime.DIM_ATTR_KEY);
+        }
+
+        public static RemoveDimAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.RemoveDimAttributeNodeGen.create();
+        }
+
+        @Override
+        @Specialization
+        protected void removeAttrFallback(DynamicObject attrs) {
+            super.removeAttrFallback(attrs);
+        }
+
+    }
+
+    public abstract static class GetDimAttributeNode extends GetFixedAttributeNode {
+
+        private final BranchProfile isLanguageProfile = BranchProfile.create();
+        private final BranchProfile isPairListProfile = BranchProfile.create();
+        private final ConditionProfile nullDimsProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile nonEmptyDimsProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile twoDimsOrMoreProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile isContainerProfile = ConditionProfile.createBinaryProfile();
+
+        protected GetDimAttributeNode() {
+            super(RRuntime.DIM_ATTR_KEY);
+        }
+
+        public static GetDimAttributeNode create() {
+            return GetDimAttributeNodeGen.create();
+        }
+
+        public final int[] getDimensions(Object x) {
+            // Let's handle the following two types directly so as to avoid wrapping and unwrapping
+            // RIntVector. The getContainerDims spec would be invoked otherwise.
+            if (x instanceof RLanguage) {
+                isLanguageProfile.enter();
+                return ((RLanguage) x).getDimensions();
+            }
+            if (x instanceof RPairList) {
+                isPairListProfile.enter();
+                return ((RPairList) x).getDimensions();
+            }
+            RIntVector dims = (RIntVector) execute(x);
+            return nullDimsProfile.profile(dims == null) ? null : dims.getInternalStore();
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getScalarVectorDims(@SuppressWarnings("unused") RScalarVector x) {
+            return null;
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getScalarVectorDims(@SuppressWarnings("unused") RSequence x) {
+            return null;
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorDims(RAbstractVector x,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            return super.getAttrFromAttributable(x, attrNullProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getContainerDims(RAbstractContainer x,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile nullResultProfile) {
+            int[] res = xTypeProfile.profile(x).getDimensions();
+            return nullResultProfile.profile(res == null) ? null : RDataFactory.createIntVector(res, true);
+        }
+
+        public int nrows(Object x) {
+            if (isContainerProfile.profile(x instanceof RAbstractContainer)) {
+                RAbstractContainer xa = (RAbstractContainer) x;
+                int[] dims = getDimensions(xa);
+                if (nonEmptyDimsProfile.profile(dims != null && dims.length > 0)) {
+                    return dims[0];
+                } else {
+                    return xa.getLength();
+                }
+            } else {
+                throw RError.error(RError.SHOW_CALLER2, RError.Message.OBJECT_NOT_MATRIX);
+            }
+        }
+
+        public int ncols(Object x) {
+            if (isContainerProfile.profile(x instanceof RAbstractContainer)) {
+                RAbstractContainer xa = (RAbstractContainer) x;
+                int[] dims = getDimensions(xa);
+                if (nonEmptyDimsProfile.profile(dims != null && dims.length > 0)) {
+                    if (twoDimsOrMoreProfile.profile(dims.length >= 2)) {
+                        return dims[1];
+                    } else {
+                        return 1;
+                    }
+                } else {
+                    return 1;
+                }
+            } else {
+                throw RError.error(RError.SHOW_CALLER2, RError.Message.OBJECT_NOT_MATRIX);
+            }
+        }
+
+    }
+
+    public abstract static class SetDimNamesAttributeNode extends SetSpecialAttributeNode {
+
+        private final ConditionProfile nullDimNamesProfile = ConditionProfile.createBinaryProfile();
+
+        protected SetDimNamesAttributeNode() {
+            super(RRuntime.DIMNAMES_ATTR_KEY);
+        }
+
+        public static SetDimNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetDimNamesAttributeNodeGen.create();
+        }
+
+        public void setDimNames(RAbstractContainer x, RList dimNames) {
+            if (nullDimNamesProfile.profile(dimNames == null)) {
+                execute(x, RNull.instance);
+            } else {
+                execute(x, dimNames);
+            }
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void resetDimNames(RAbstractContainer x, @SuppressWarnings("unused") RNull rnull,
+                        @Cached("create()") RemoveDimNamesAttributeNode removeDimNamesAttrNode) {
+            removeDimNamesAttrNode.execute(x);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setDimNamesInVector(RVector<?> x, RList newDimNames,
+                        @Cached("create()") GetDimAttributeNode getDimNode,
+                        @Cached("create()") BranchProfile nullDimsProfile,
+                        @Cached("create()") BranchProfile dimsLengthProfile,
+                        @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
+                        @Cached("create()") BranchProfile invalidDimProfile,
+                        @Cached("create()") BranchProfile nullDimProfile,
+                        @Cached("create()") BranchProfile resizeDimsProfile,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            int[] dimensions = getDimNode.getDimensions(x);
+            if (dimensions == null) {
+                nullDimsProfile.enter();
+                throw RError.error(this, RError.Message.DIMNAMES_NONARRAY);
+            }
+            int newDimNamesLength = newDimNames.getLength();
+            if (newDimNamesLength > dimensions.length) {
+                dimsLengthProfile.enter();
+                throw RError.error(this, RError.Message.DIMNAMES_DONT_MATCH_DIMS, newDimNamesLength,
+                                dimensions.length);
+            }
+
+            loopProfile.profileCounted(newDimNamesLength);
+            for (int i = 0; loopProfile.inject(i < newDimNamesLength); i++) {
+                Object dimObject = newDimNames.getDataAt(i);
+
+                if ((dimObject instanceof String && dimensions[i] != 1) ||
+                                (dimObject instanceof RStringVector && !isValidDimLength((RStringVector) dimObject, dimensions[i]))) {
+                    invalidDimProfile.enter();
+                    throw RError.error(this, RError.Message.DIMNAMES_DONT_MATCH_EXTENT, i + 1);
+                }
+
+                if (dimObject == null || (dimObject instanceof RStringVector && ((RStringVector) dimObject).getLength() == 0)) {
+                    nullDimProfile.enter();
+                    newDimNames.updateDataAt(i, RNull.instance, null);
+                }
+            }
+
+            RList resDimNames = newDimNames;
+            if (newDimNamesLength < dimensions.length) {
+                resizeDimsProfile.enter();
+                // resize the array and fill the missing entries with NULL-s
+                resDimNames = (RList) resDimNames.copyResized(dimensions.length, true);
+                resDimNames.setAttributes(newDimNames);
+                for (int i = newDimNamesLength; i < dimensions.length; i++) {
+                    resDimNames.updateDataAt(i, RNull.instance, null);
+                }
+            }
+            resDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
+
+            if (x.getAttributes() == null) {
+                attrNullProfile.enter();
+                x.initAttributes(RAttributesLayout.createDimNames(resDimNames));
+                return;
+            }
+
+            super.setAttrInAttributable(x, resDimNames, attrNullProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        private static boolean isValidDimLength(RStringVector x, int expectedDim) {
+            int len = x.getLength();
+            return len == 0 || len == expectedDim;
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setDimNamesInContainer(RAbstractContainer x, RList dimNames, @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setDimNames(dimNames);
+        }
+
+    }
+
+    public abstract static class RemoveDimNamesAttributeNode extends RemoveSpecialAttributeNode {
+
+        protected RemoveDimNamesAttributeNode() {
+            super(RRuntime.DIMNAMES_ATTR_KEY);
+        }
+
+        @Override
+        @Specialization
+        protected void removeAttrFallback(DynamicObject attrs) {
+            super.removeAttrFallback(attrs);
+        }
+
+        public static RemoveDimNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.RemoveDimNamesAttributeNodeGen.create();
+        }
+    }
+
+    public abstract static class GetDimNamesAttributeNode extends GetFixedAttributeNode {
+
+        protected GetDimNamesAttributeNode() {
+            super(RRuntime.DIMNAMES_ATTR_KEY);
+        }
+
+        public static GetDimNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.GetDimNamesAttributeNodeGen.create();
+        }
+
+        public final RList getDimNames(Object x) {
+            return (RList) execute(x);
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorDimNames(RVector<?> x,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            return super.getAttrFromAttributable(x, attrNullProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorDimNames(RAbstractContainer x,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") RAttributeProfiles attrProfiles) {
+            return xTypeProfile.profile(x).getDimNames(attrProfiles);
+        }
+
+    }
+
+    public abstract static class SetRowNamesAttributeNode extends SetSpecialAttributeNode {
+
+        private final ConditionProfile nullRowNamesProfile = ConditionProfile.createBinaryProfile();
+
+        protected SetRowNamesAttributeNode() {
+            super(RRuntime.ROWNAMES_ATTR_KEY);
+        }
+
+        public static SetRowNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetRowNamesAttributeNodeGen.create();
+        }
+
+        public void setRowNames(RAbstractContainer x, RAbstractVector rowNames) {
+            if (nullRowNamesProfile.profile(rowNames == null)) {
+                execute(x, RNull.instance);
+            } else {
+                execute(x, rowNames);
+            }
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void resetRowNames(RVector<?> x, @SuppressWarnings("unused") RNull rnull,
+                        @Cached("create()") RemoveRowNamesAttributeNode removeRowNamesAttrNode) {
+            removeRowNamesAttrNode.execute(x);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setRowNamesInVector(RVector<?> x, RAbstractVector newRowNames,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            if (x.getAttributes() == null) {
+                attrNullProfile.enter();
+                x.initAttributes(RAttributesLayout.createRowNames(newRowNames));
+                return;
+            }
+            setAttrInAttributable(x, newRowNames, attrNullProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void setRowNamesInContainer(RAbstractContainer x, RAbstractVector rowNames, @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setRowNames(rowNames);
+        }
+
+    }
+
+    public abstract static class RemoveRowNamesAttributeNode extends RemoveSpecialAttributeNode {
+
+        protected RemoveRowNamesAttributeNode() {
+            super(RRuntime.DIMNAMES_ATTR_KEY);
+        }
+
+        public static RemoveRowNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.RemoveRowNamesAttributeNodeGen.create();
+        }
+
+        @Override
+        @Specialization
+        protected void removeAttrFallback(DynamicObject attrs) {
+            super.removeAttrFallback(attrs);
+        }
+    }
+
+    public abstract static class GetRowNamesAttributeNode extends GetFixedAttributeNode {
+
+        protected GetRowNamesAttributeNode() {
+            super(RRuntime.ROWNAMES_ATTR_KEY);
+        }
+
+        public static GetRowNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.GetRowNamesAttributeNodeGen.create();
+        }
+
+        public Object getRowNames(RAbstractContainer x) {
+            return execute(x);
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getScalarVectorRowNames(@SuppressWarnings("unused") RScalarVector x) {
+            return RNull.instance;
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getScalarVectorRowNames(@SuppressWarnings("unused") RSequence x) {
+            return RNull.class;
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorRowNames(RAbstractVector x,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile nullRowNamesProfile) {
+            Object res = super.getAttrFromAttributable(x, attrNullProfile, attrStorageProfile, xTypeProfile);
+            return nullRowNamesProfile.profile(res == null) ? RNull.instance : res;
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorRowNames(RAbstractContainer x,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") RAttributeProfiles attrProfiles) {
+            return xTypeProfile.profile(x).getRowNames(attrProfiles);
+        }
+
+    }
+
+    public abstract static class SetClassAttributeNode extends SetSpecialAttributeNode {
+
+        protected SetClassAttributeNode() {
+            super(RRuntime.CLASS_ATTR_KEY);
+        }
+
+        public static SetClassAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetClassAttributeNodeGen.create();
+        }
+
+        public void reset(RAttributable x) {
+            execute(x, RNull.instance);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected <T> void handleVectorNullClass(RVector<T> vector, @SuppressWarnings("unused") RNull classAttr,
+                        @Cached("createClass()") RemoveFixedAttributeNode removeClassAttrNode,
+                        @Cached("createBinaryProfile()") ConditionProfile initAttrProfile,
+                        @Cached("create()") BranchProfile nullAttrProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            handleVector(vector, null, removeClassAttrNode, initAttrProfile, nullAttrProfile, nullClassProfile, notNullClassProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected <T> void handleVector(RVector<T> vector, RStringVector classAttr,
+                        @Cached("createClass()") RemoveFixedAttributeNode removeClassAttrNode,
+                        @Cached("createBinaryProfile()") ConditionProfile initAttrProfile,
+                        @Cached("create()") BranchProfile nullAttrProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+
+            DynamicObject attrs = vector.getAttributes();
+            boolean initializeAttrs = initAttrProfile.profile(attrs == null && classAttr != null && classAttr.getLength() != 0);
+            if (initializeAttrs) {
+                nullAttrProfile.enter();
+                attrs = RAttributesLayout.createClass(classAttr);
+                vector.initAttributes(attrs);
+            }
+            if (nullClassProfile.profile(attrs != null && (classAttr == null || classAttr.getLength() == 0))) {
+                removeAttributeMapping(vector, attrs, removeClassAttrNode);
+            } else if (notNullClassProfile.profile(classAttr != null && classAttr.getLength() != 0)) {
+                for (int i = 0; i < classAttr.getLength(); i++) {
+                    String attr = classAttr.getDataAt(i);
+                    if (RRuntime.CLASS_FACTOR.equals(attr)) {
+                        // TODO: Isn't this redundant when the same operation is done after the
+                        // loop?
+                        if (!initializeAttrs) {
+                            super.setAttrInAttributable(vector, classAttr, nullAttrProfile, attrStorageProfile, xTypeProfile);
+                        }
+                        // setClassAttrNode.execute(attrs, classAttr);
+                        if (vector.getElementClass() != RInteger.class) {
+                            // N.B. there used to be conversion to integer under certain
+                            // circumstances.
+                            // However, it seems that it was dead/obsolete code so it was removed.
+                            // Notes: this can only happen if the class is set by hand to some
+                            // non-integral vector, i.e. attr(doubles, 'class') <- 'factor'. GnuR
+                            // also
+                            // does not update the 'class' attr with other, possibly
+                            // valid classes when it reaches this error.
+                            throw RError.error(RError.SHOW_CALLER2, RError.Message.ADDING_INVALID_CLASS, "factor");
+                        }
+                    }
+                }
+
+                if (!initializeAttrs) {
+                    super.setAttrInAttributable(vector, classAttr, nullAttrProfile, attrStorageProfile, xTypeProfile);
+                }
+            }
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void handleAttributable(RAttributable x, @SuppressWarnings("unused") RNull classAttr) {
+            x.setClassAttr(null);
+        }
+
+        @Specialization(insertBefore = "setAttrInAttributable")
+        protected void handleAttributable(RAttributable x, RStringVector classAttr) {
+            x.setClassAttr(classAttr);
+        }
+
+        private static void removeAttributeMapping(RAttributable x, DynamicObject attrs, RemoveFixedAttributeNode removeClassAttrNode) {
+            if (attrs != null) {
+                removeClassAttrNode.execute(attrs);
+                if (attrs.isEmpty()) {
+                    x.initAttributes(null);
+                }
+            }
+        }
+
+    }
+
+    public abstract static class RemoveClassAttributeNode extends RemoveSpecialAttributeNode {
+
+        protected RemoveClassAttributeNode() {
+            super(RRuntime.CLASS_ATTR_KEY);
+        }
+
+        public static RemoveClassAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.RemoveClassAttributeNodeGen.create();
+        }
+
+        @Override
+        @Specialization
+        protected void removeAttrFallback(DynamicObject attrs) {
+            super.removeAttrFallback(attrs);
+        }
+
+    }
+
+    public abstract static class GetClassAttributeNode extends GetFixedAttributeNode {
+
+        protected GetClassAttributeNode() {
+            super(RRuntime.CLASS_ATTR_KEY);
+        }
+
+        public static GetClassAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.GetClassAttributeNodeGen.create();
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorClass(RVector<?> x,
+                        @Cached("create()") BranchProfile attrNullProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+            return super.getAttrFromAttributable(x, attrNullProfile, attrStorageProfile, xTypeProfile);
+        }
+
+        @Specialization(insertBefore = "getAttrFromAttributable")
+        protected Object getVectorClass(RAbstractContainer x,
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") RAttributeProfiles attrProfiles) {
+            return xTypeProfile.profile(x).getClassAttr(attrProfiles);
+        }
+
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java
index 16ae928994e5501164d6c035d71ee336d91c4284..c31cd1da74a52ee0c2792e5dba579aafb2a7be56 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java
@@ -26,8 +26,10 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -47,7 +49,9 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
 
     protected final boolean copyAllAttributes;
 
-    protected final RAttributeProfiles attrSourceProfiles = RAttributeProfiles.create();
+    @Child protected HasFixedAttributeNode hasDimNode = HasFixedAttributeNode.createDim();
+    @Child protected GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
+    @Child protected GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     protected UnaryCopyAttributesNode(boolean copyAllAttributes) {
         this.copyAllAttributes = copyAllAttributes;
@@ -59,13 +63,13 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
 
     public abstract RAbstractVector execute(RAbstractVector target, RAbstractVector left);
 
-    protected boolean containsMetadata(RAbstractVector vector, RAttributeProfiles attrProfiles) {
-        return vector instanceof RVector && vector.hasDimensions() || (copyAllAttributes && vector.getAttributes() != null) || vector.getNames(attrProfiles) != null ||
-                        vector.getDimNames(attrProfiles) != null;
+    protected boolean containsMetadata(RAbstractVector vector) {
+        return vector instanceof RVector && hasDimNode.execute(vector) || (copyAllAttributes && vector.getAttributes() != null) || getNamesNode.getNames(vector) != null ||
+                        getDimNamesNode.getDimNames(vector) != null;
     }
 
     @SuppressWarnings("unused")
-    @Specialization(guards = "!containsMetadata(source, attrSourceProfiles)")
+    @Specialization(guards = "!containsMetadata(source)")
     protected RAbstractVector copyNoMetadata(RAbstractVector target, RAbstractVector source) {
         return target;
     }
@@ -76,7 +80,7 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
         return target;
     }
 
-    @Specialization(guards = {"!copyAllAttributes || target != source", "containsMetadata(source, attrSourceProfiles)"})
+    @Specialization(guards = {"!copyAllAttributes || target != source", "containsMetadata(source)"})
     protected RAbstractVector copySameLength(RAbstractVector target, RAbstractVector source, //
                     @Cached("create()") CopyOfRegAttributesNode copyOfReg, //
                     @Cached("createDim()") RemoveFixedAttributeNode removeDim, //
@@ -87,40 +91,36 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
                     @Cached("createDimNames()") SetFixedAttributeNode putDimNames, //
                     @Cached("createBinaryProfile()") ConditionProfile noDimensions, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNamesSource, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
+                    @Cached("createBinaryProfile()") ConditionProfile hasDimNames,
+                    @Cached("create()") GetDimAttributeNode getDimsNode) {
         RVector<?> result = target.materialize();
 
         if (copyAllAttributes) {
             copyOfReg.execute(source, result);
         }
 
-        int[] newDimensions = source.getDimensions();
+        int[] newDimensions = getDimsNode.getDimensions(source);
         if (noDimensions.profile(newDimensions == null)) {
             DynamicObject attributes = result.getAttributes();
             if (attributes != null) {
                 removeDim.execute(attributes);
                 removeDimNames.execute(attributes);
-                result.setInternalDimNames(null);
             }
-            result.setInternalDimensions(null);
 
-            RStringVector vecNames = source.getNames(attrSourceProfiles);
+            RStringVector vecNames = getNamesNode.getNames(source);
             if (hasNamesSource.profile(vecNames != null)) {
                 putNames.execute(initAttributes.execute(result), vecNames);
-                result.setInternalNames(vecNames);
                 return result;
             }
             return result;
         }
 
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
 
-        RList newDimNames = source.getDimNames(attrSourceProfiles);
+        RList newDimNames = getDimNamesNode.getDimNames(source);
         if (hasDimNames.profile(newDimNames != null)) {
             putDimNames.execute(result.getAttributes(), newDimNames);
             newDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
-            result.setInternalDimNames(newDimNames);
             return result;
         }
         return result;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java
index d535ea92bc02fa1d2c8c9afeac907fcbb0c97534..7d7294095202e7f5ee95e789e947a12832a2e9c4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RExternalBuiltinNode.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -74,7 +73,6 @@ public abstract class RExternalBuiltinNode extends RBaseNode {
     @Child private CastToVectorNode castVector;
     @Children private final CastNode[] argumentCasts;
 
-    protected final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     protected final BranchProfile errorProfile = BranchProfile.create();
 
     public RExternalBuiltinNode() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java
index 9c9ffffb388f84c5819887d65e8721dc07ed7048..3acb958ef9701fc0229a07e17fafe3d69a94c9f3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/CollectGenericArgumentsNode.java
@@ -45,6 +45,8 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
+// transcribed from /src/library/methods/src/methods_list_dispatch.c (R_dispatch_generic function)
+
 /*
  * Used to collect arguments of the generic function for S4 method dispatch. Modeled after {@link CollectArgumentsNode}.
  */
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
index 733648fbaea8f503607b1b735e07275a000315ab..ea03075c9a6fe23cf2c4ba80440876339b94c4c8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
@@ -30,6 +30,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
+// transcribed from /src/library/methods/src/methods_list_dispatch.c (R_dispatch_generic function)
 public abstract class DispatchGeneric extends RBaseNode {
 
     public abstract Object executeObject(VirtualFrame frame, REnvironment mtable, RStringVector classes, RFunction fdef, String fname);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java
index 1e450fd0305ce0255954e667cf2816950dfce822..84229b57ef0d5313013909ec59ce9d622496bc0c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetPrimName.java
@@ -17,7 +17,7 @@ import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RFunction;
 
-// transcribed from src/library/methods/utils.c
+// transcribed from src/library/methods/src/utils.c
 public abstract class GetPrimName extends RExternalBuiltinNode.Arg1 {
 
     @Specialization(guards = "f.isBuiltin()")
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
index 3b7dc03d2d930df8d37386cc0fd332e510823f56..8dc96975ebadf202edc586ede634c365eb3475df 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
@@ -19,6 +19,7 @@ import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
@@ -28,7 +29,6 @@ import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RShareable;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 
 // transcribed from src/main/attrib.c
@@ -42,6 +42,7 @@ public abstract class GetS4DataSlot extends Node {
     @Child private GetFixedAttributeNode dotDataAttrAccess;
     @Child private GetFixedAttributeNode dotXDataAttrAccess;
     @Child private TypeofNode typeOf = TypeofNodeGen.create();
+    @Child private SetClassAttributeNode setClassAttrNode;
 
     private final BranchProfile shareable = BranchProfile.create();
 
@@ -72,6 +73,12 @@ public abstract class GetS4DataSlot extends Node {
                 shareable.enter();
                 obj = (RAttributable) ((RShareable) obj).copy();
             }
+
+            if (setClassAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setClassAttrNode = insert(SetClassAttributeNode.create());
+            }
+
             if (s3Class != null) {
                 if (s3ClassAttrRemove == null) {
                     assert castToVector == null;
@@ -81,9 +88,9 @@ public abstract class GetS4DataSlot extends Node {
 
                 }
                 s3ClassAttrRemove.execute(obj.initAttributes());
-                obj = obj.setClassAttr((RStringVector) castToVector.execute(s3Class));
+                setClassAttrNode.execute(obj, castToVector.execute(s3Class));
             } else {
-                obj = obj.setClassAttr(null);
+                setClassAttrNode.reset(obj);
             }
             obj.unsetS4();
             if (type == RType.S4Object) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
index 71ae3eef2b2593978101505c6d1e786b381b4e53..4be981a574ff0db8c4c8bfb736f99a60452b1748 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
@@ -39,6 +39,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
+// transcribed from /src/library/methods/src/methods_list_dispatch.c (R_loadMethod function)
 abstract class LoadMethod extends RBaseNode {
 
     private static final ArgumentsSignature SIGNATURE = ArgumentsSignature.get("method", "fname", "envir");
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
index b02d46ea7312a68103d2a0488edad5a155c4bc29..025378e9745a42cfa016d1f36041b5e97e88b84b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
@@ -12,10 +12,12 @@
  */
 package com.oracle.truffle.r.nodes.objects;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
@@ -26,7 +28,6 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 
 // transcribed from src/main/objects.c
 public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
@@ -36,6 +37,7 @@ public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
     @Child private AccessSlotNode accessSlotPrototypeName = AccessSlotNodeGen.create(true, null, null);
     @Child private DuplicateNode duplicate = DuplicateNodeGen.create(true);
     @Child private GetFixedAttributeNode pckgAttrAccess = GetFixedAttributeNode.create(RRuntime.PCKG_ATTR_KEY);
+    @Child private SetClassAttributeNode setClassAttrNode;
 
     @Child private CastNode castStringScalar;
     @Child private CastNode castLogicalScalar;
@@ -62,7 +64,13 @@ public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
         RAttributable valueAttr = (RAttributable) value;
         if (valueAttr instanceof RS4Object ||
                         (e instanceof RAttributable && ((RAttributable) e).getAttributes() != null && pckgAttrAccess.execute(((RAttributable) e).getAttributes()) != null)) {
-            valueAttr = valueAttr.setClassAttr((RStringVector) e);
+
+            if (setClassAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setClassAttrNode = insert(SetClassAttributeNode.create());
+            }
+
+            setClassAttrNode.execute(valueAttr, e);
             valueAttr.setS4();
         }
         return value;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
index bb33f7c87e692865c85bb056adbd3b6cb32987b2..a720fcbc354a2185eb2dfda7551dedf61aa7cce1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
@@ -29,6 +29,8 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNodeGen;
+import com.oracle.truffle.r.nodes.attributes.HasFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.primitive.BinaryMapNodeFactory.VectorMapBinaryInternalNodeGen;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -63,6 +65,10 @@ public final class BinaryMapNode extends RBaseNode {
     @Child private VectorMapBinaryInternalNode vectorNode;
     @Child private BinaryMapFunctionNode function;
     @Child private CopyAttributesNode copyAttributes;
+    @Child private GetDimAttributeNode getLeftDimNode = GetDimAttributeNode.create();
+    @Child private GetDimAttributeNode getRightDimNode = GetDimAttributeNode.create();
+    @Child private HasFixedAttributeNode hasLeftDimNode = HasFixedAttributeNode.createDim();
+    @Child private HasFixedAttributeNode hasRightDimNode = HasFixedAttributeNode.createDim();
 
     // profiles
     private final Class<? extends RAbstractVector> leftClass;
@@ -142,9 +148,9 @@ public final class BinaryMapNode extends RBaseNode {
         }
     }
 
-    private static boolean differentDimensions(RAbstractVector left, RAbstractVector right) {
-        int[] leftDimensions = left.getDimensions();
-        int[] rightDimensions = right.getDimensions();
+    private boolean differentDimensions(RAbstractVector left, RAbstractVector right) {
+        int[] leftDimensions = getLeftDimNode.getDimensions(left);
+        int[] rightDimensions = getRightDimNode.getDimensions(right);
         int leftLength = leftDimensions.length;
         int rightLength = rightDimensions.length;
         if (leftLength != rightLength) {
@@ -227,7 +233,7 @@ public final class BinaryMapNode extends RBaseNode {
     }
 
     private Object applyVectorized(RAbstractVector left, RAbstractVector leftCast, int leftLength, RAbstractVector right, RAbstractVector rightCast, int rightLength) {
-        if (mayContainMetadata && (dimensionsProfile.profile(left.hasDimensions() && right.hasDimensions()))) {
+        if (mayContainMetadata && (dimensionsProfile.profile(hasLeftDimNode.execute(left) && hasRightDimNode.execute(right)))) {
             if (differentDimensions(left, right)) {
                 CompilerDirectives.transferToInterpreter();
                 throw RError.error(this, RError.Message.NON_CONFORMABLE_ARRAYS);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
index bb49fe7f101598457022b1d5854d3b0901d8de16..e0b9d614cae4b1e9d6a0fff7d469b945ce70213c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
@@ -22,12 +22,18 @@
  */
 package com.oracle.truffle.r.nodes.primitive;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.HasFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.primitive.UnaryMapNodeFactory.MapUnaryVectorInternalNodeGen;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -50,6 +56,9 @@ public final class UnaryMapNode extends RBaseNode {
 
     @Child private UnaryMapFunctionNode scalarNode;
     @Child private MapUnaryVectorInternalNode vectorNode;
+    @Child private GetDimAttributeNode getDimNode;
+    @Child private SetDimAttributeNode setDimNode;
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     // profiles
     private final Class<? extends RAbstractVector> operandClass;
@@ -170,6 +179,19 @@ public final class UnaryMapNode extends RBaseNode {
         if (containsMetadata(operand) && operand != target) {
             hasAttributesProfile.enter();
             result = result.materialize();
+
+            if (getDimNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getDimNode = insert(GetDimAttributeNode.create());
+            }
+
+            if (setDimNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setDimNode = insert(SetDimAttributeNode.create());
+            }
+
+            setDimNode.setDimensions(result, getDimNode.getDimensions(operand));
+
             copyAttributesInternal((RVector<?>) result, operand);
         }
         return result;
@@ -178,16 +200,18 @@ public final class UnaryMapNode extends RBaseNode {
     private final ConditionProfile hasDimensionsProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile hasNamesProfile = ConditionProfile.createBinaryProfile();
 
+    @Child private HasFixedAttributeNode hasDimNode = HasFixedAttributeNode.createDim();
+    @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
+
     private boolean containsMetadata(RAbstractVector vector) {
         return vector instanceof RVector &&
-                        (hasDimensionsProfile.profile(vector.hasDimensions()) || vector.getAttributes() != null || hasNamesProfile.profile(vector.getNames(attrProfiles) != null) ||
-                                        vector.getDimNames(attrProfiles) != null);
+                        (hasDimensionsProfile.profile(hasDimNode.execute(vector)) || vector.getAttributes() != null || hasNamesProfile.profile(getNamesNode.getNames(vector) != null) ||
+                                        getDimNamesNode.getDimNames(vector) != null);
     }
 
     @TruffleBoundary
     private void copyAttributesInternal(RVector<?> result, RAbstractVector attributeSource) {
         result.copyRegAttributesFrom(attributeSource);
-        result.setDimensions(attributeSource.getDimensions());
         result.copyNamesFrom(attrProfiles, attributeSource);
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
index e9b89627095e03cd06329d0eee7a0082a7ea2ab5..860e6461885dec3ed983f115cc5e3e2b81ca9abe 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
@@ -22,17 +22,21 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.runtime.NullProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
@@ -46,7 +50,10 @@ public abstract class CastBaseNode extends CastNode {
     private final ConditionProfile hasDimNamesProfile = ConditionProfile.createBinaryProfile();
     private final NullProfile hasDimensionsProfile = NullProfile.create();
     private final NullProfile hasNamesProfile = NullProfile.create();
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
+    @Child private GetDimAttributeNode getDimNode;
+    @Child private SetDimNamesAttributeNode setDimNamesNode;
+    @Child private GetDimNamesAttributeNode getDimNamesNode;
 
     private final boolean preserveNames;
     private final boolean preserveDimensions;
@@ -56,13 +63,16 @@ public abstract class CastBaseNode extends CastNode {
         this.preserveNames = preserveNames;
         this.preserveDimensions = preserveDimensions;
         this.preserveAttributes = preserveAttributes;
+        if (preserveDimensions) {
+            getDimNamesNode = GetDimNamesAttributeNode.create();
+        }
     }
 
     public boolean preserveNames() {
         return preserveNames;
     }
 
-    public boolean preserveDimensions() {
+    public final boolean preserveDimensions() {
         return preserveDimensions;
     }
 
@@ -79,7 +89,11 @@ public abstract class CastBaseNode extends CastNode {
 
     protected int[] getPreservedDimensions(RAbstractContainer operand) {
         if (preserveDimensions()) {
-            return hasDimensionsProfile.profile(operand.getDimensions());
+            if (getDimNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getDimNode = insert(GetDimAttributeNode.create());
+            }
+            return hasDimensionsProfile.profile(getDimNode.getDimensions(operand));
         } else {
             return null;
         }
@@ -87,7 +101,7 @@ public abstract class CastBaseNode extends CastNode {
 
     protected RStringVector getPreservedNames(RAbstractContainer operand) {
         if (preserveNames()) {
-            return hasNamesProfile.profile(operand.getNames(attrProfiles));
+            return hasNamesProfile.profile(getNamesNode.getNames(operand));
         } else {
             return null;
         }
@@ -95,9 +109,13 @@ public abstract class CastBaseNode extends CastNode {
 
     protected void preserveDimensionNames(RAbstractContainer operand, RVector<?> ret) {
         if (preserveDimensions()) {
-            RList dimNames = operand.getDimNames(attrProfiles);
+            RList dimNames = getDimNamesNode.getDimNames(operand);
             if (hasDimNamesProfile.profile(dimNames != null)) {
-                ret.setDimNames((RList) dimNames.copy());
+                if (setDimNamesNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    setDimNamesNode = insert(SetDimNamesAttributeNode.create());
+                }
+                setDimNamesNode.setDimNames(ret, (RList) dimNames.copy());
             }
         }
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
index 60f816057c901fbe6863f0c7cc5460d7c54c4cf1..1178f3762ee7743577fe611918c14242c8f9592d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java
@@ -22,10 +22,11 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -36,8 +37,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 
 public abstract class CastExpressionNode extends CastBaseNode {
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
-
     public abstract Object executeExpression(Object o);
 
     protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
@@ -85,7 +84,8 @@ public abstract class CastExpressionNode extends CastBaseNode {
     }
 
     @Specialization
-    protected RExpression doAbstractContainer(RAbstractContainer obj) {
+    protected RExpression doAbstractContainer(RAbstractContainer obj,
+                    @Cached("create()") GetNamesAttributeNode getNamesNode) {
         int len = obj.getLength();
         Object[] data = new Object[len];
         for (int i = 0; i < len; i++) {
@@ -94,7 +94,7 @@ public abstract class CastExpressionNode extends CastBaseNode {
         if (obj instanceof RList) {
             RList list = (RList) obj;
             // TODO other attributes
-            return RDataFactory.createExpression(data, list.getNames(attrProfiles));
+            return RDataFactory.createExpression(data, getNamesNode.getNames(list));
         } else {
             return RDataFactory.createExpression(data);
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
index 9d53e8623b97de1e410dd4ae8b0619e7fae4f224..14ea322f9f4f9e49447990349ea395b987d9f135 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
@@ -22,11 +22,14 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -38,13 +41,14 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public abstract class CastListNode extends CastBaseNode {
 
+    @Child private SetClassAttributeNode setClassAttrNode;
+
     public abstract RList executeList(Object o);
 
     protected CastListNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
@@ -86,16 +90,24 @@ public abstract class CastListNode extends CastBaseNode {
     }
 
     @Specialization
-    protected RList doLanguage(RLanguage operand, @Cached("create()") ArrayAttributeNode attrAttrAccess) {
+    protected RList doLanguage(RLanguage operand,
+                    @Cached("create()") ArrayAttributeNode attrAttrAccess,
+                    @Cached("create()") SetAttributeNode setAttrNode) {
         RList result = RContext.getRRuntimeASTAccess().asList(operand);
         DynamicObject operandAttrs = operand.getAttributes();
         if (operandAttrs != null) {
             // result may already have names, so can't call RVector.copyAttributesFrom
             for (RAttributesLayout.RAttribute attr : attrAttrAccess.execute(operandAttrs)) {
                 if (attr.getName().equals(RRuntime.CLASS_ATTR_KEY)) {
-                    result.setClassAttr((RStringVector) attr.getValue());
+
+                    if (setClassAttrNode == null) {
+                        setClassAttrNode = insert(SetClassAttributeNode.create());
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                    }
+
+                    setClassAttrNode.execute(result, attr.getValue());
                 } else {
-                    result.setAttr(attr.getName(), attr.getValue());
+                    setAttrNode.execute(result, attr.getName(), attr.getValue());
                 }
             }
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
index 084a71a45255baab8f18c0adbdc809882a9ba399..f6c14178278012d0d955b85109470e9667a1a166 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java
@@ -207,6 +207,7 @@ public abstract class ToStringNode extends RBaseNode {
 
     @SuppressWarnings("unused")
     @Specialization
+    @TruffleBoundary
     protected String toString(REnvironment env, boolean quotes, String separator) {
         return env.toString();
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
index f46b860eaa0bb01f6161abce902c1a7bd32ae362..11fc0d9c9361611a2cf8e797fdf7282527963218 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java
@@ -110,7 +110,7 @@ public abstract class UnaryNotNode extends RBuiltinNode {
             }
         }
         RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA());
-        resultVector.copyAttributesFrom(attrProfiles, vector);
+        resultVector.copyAttributesFrom(vector);
         return resultVector;
     }
 
@@ -184,7 +184,7 @@ public abstract class UnaryNotNode extends RBuiltinNode {
             }
         }
         RRawVector resultVector = RDataFactory.createRawVector(result);
-        resultVector.copyAttributesFrom(attrProfiles, vector);
+        resultVector.copyAttributesFrom(vector);
         return resultVector;
     }
 
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java
similarity index 66%
rename from com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper.java
rename to com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java
index fa73127bcec10decf22135b9317a62cbf70d5ce1..d51986b5013153204a5c9b511534bd21d37f4de5 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/CallRFFIHelper.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java
@@ -20,12 +20,11 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.runtime.ffi.jni;
+package com.oracle.truffle.r.runtime.ffi;
 
 import java.nio.charset.StandardCharsets;
 import java.util.function.Function;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.object.DynamicObject;
@@ -79,17 +78,16 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
+import com.oracle.truffle.r.runtime.ffi.ParseResult.ParseStatus;
+import com.oracle.truffle.r.runtime.ffi.jni.TraceUpCallsAdapter;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
 import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.rng.RRNG;
 
 /**
- * This class provides methods that match the functionality of the macro/function definitions in the
- * R header files, e.g. {@code Rinternals.h} that are used by C/C++ code. For ease of
- * identification, we use method names that, as far as possible, match the names in the header
- * files. These methods should never be called from normal FastR code.
+ * This class provides a simple Java-based implementation of {@link UpCallsRFFI}, using no Truffle
+ * mechanisms.
  *
  * TODO Many of the implementations here are incomplete and/or duplicate code that exists in the
  * Truffle side of the implementation, i.e., {@link RNode} subclasses. A complete refactoring that
@@ -98,37 +96,16 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
  * is desirable. In some cases it may be possible to "implement" the functions in R (which is a
  * simple way to achieve the above).
  */
-public class CallRFFIHelper {
+public class JavaUpCallsRFFI implements UpCallsRFFI {
 
-    /**
-     * Internally GNU R distinguishes "strings" and "vectors of strings" using the {@code CHARSXP}
-     * and {@code STRSXP} types, respectively. Although this difference is invisible at the R level,
-     * it manifests itself in the R FFI as several functions traffic in the {@code CHARSXP} type.
-     * Since FastR already uses {@code String} to denote a length-1 string vector, it cannot be used
-     * to represent a {@code CHARSXP}, so this class exists to do so.
-     *
-     */
-    public static final class CharSXPWrapper {
-        private final String contents;
-
-        CharSXPWrapper(String contents) {
-            this.contents = contents;
-        }
-
-        public String getContents() {
-            return contents;
-        }
+    private TraceUpCallsAdapter tracer;
 
-        @Override
-        public String toString() {
-            return "CHARSXP(" + contents + ")";
+    public JavaUpCallsRFFI() {
+        if (RFFIUtils.traceEnabled()) {
+            tracer = new TraceUpCallsAdapter();
         }
     }
 
-    public static Object createCharSXP(String contents) {
-        return new CharSXPWrapper(contents);
-    }
-
     private static RuntimeException unimplemented() {
         return unimplemented("");
     }
@@ -169,38 +146,43 @@ public class CallRFFIHelper {
 
     // Checkstyle: stop method name check
 
-    public static RIntVector Rf_ScalarInteger(int value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
+    @Override
+    public RIntVector Rf_ScalarInteger(int value) {
+        if (tracer != null) {
+            tracer.Rf_ScalarInteger(value);
         }
         return RDataFactory.createIntVectorFromScalar(value);
     }
 
-    public static RLogicalVector Rf_ScalarLogical(int value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
+    @Override
+    public RLogicalVector Rf_ScalarLogical(int value) {
+        if (tracer != null) {
+            tracer.Rf_ScalarLogical(value);
         }
         return RDataFactory.createLogicalVectorFromScalar(value != 0);
     }
 
-    public static RDoubleVector Rf_ScalarDouble(double value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
+    @Override
+    public RDoubleVector Rf_ScalarDouble(double value) {
+        if (tracer != null) {
+            tracer.Rf_ScalarDouble(value);
         }
         return RDataFactory.createDoubleVectorFromScalar(value);
     }
 
-    public static RStringVector Rf_ScalarString(Object value) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ScalarString", value);
+    @Override
+    public RStringVector Rf_ScalarString(Object value) {
+        if (tracer != null) {
+            tracer.Rf_ScalarString(value);
         }
         CharSXPWrapper chars = guaranteeInstanceOf(value, CharSXPWrapper.class);
         return RDataFactory.createStringVectorFromScalar(chars.getContents());
     }
 
-    public static int Rf_asInteger(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asInteger", x);
+    @Override
+    public int Rf_asInteger(Object x) {
+        if (tracer != null) {
+            tracer.Rf_asInteger(x);
         }
         // TODO this is quite incomplete and really should be implemented with CastIntegerNode
         if (x instanceof Integer) {
@@ -217,9 +199,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static double Rf_asReal(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asReal", x);
+    @Override
+    public double Rf_asReal(Object x) {
+        if (tracer != null) {
+            tracer.Rf_asReal(x);
         }
         if (x instanceof Double) {
             return ((Double) x).doubleValue();
@@ -231,9 +214,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static int Rf_asLogical(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asLogical", x);
+    @Override
+    public int Rf_asLogical(Object x) {
+        if (tracer != null) {
+            tracer.Rf_asLogical(x);
         }
         if (x instanceof Byte) {
             return ((Byte) x).intValue();
@@ -243,14 +227,15 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object Rf_asChar(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_asChar", x);
+    @Override
+    public Object Rf_asChar(Object x) {
+        if (tracer != null) {
+            tracer.Rf_asChar(x);
         }
         if (x instanceof CharSXPWrapper) {
             return x;
         } else if (x instanceof RSymbol) {
-            return new CharSXPWrapper(((RSymbol) x).getName());
+            return CharSXPWrapper.create(((RSymbol) x).getName());
         }
 
         Object obj = RRuntime.asAbstractVector(x);
@@ -258,34 +243,37 @@ public class CallRFFIHelper {
             RAbstractVector vector = (RAbstractVector) obj;
             if (vector.getLength() > 0) {
                 if (vector instanceof RAbstractStringVector) {
-                    return new CharSXPWrapper(((RAbstractStringVector) vector).getDataAt(0));
+                    return CharSXPWrapper.create(((RAbstractStringVector) vector).getDataAt(0));
                 } else {
                     unimplemented("asChar type " + x.getClass());
                 }
             }
         }
 
-        return new CharSXPWrapper(RRuntime.STRING_NA);
+        return CharSXPWrapper.create(RRuntime.STRING_NA);
     }
 
-    public static Object Rf_mkCharLenCE(byte[] bytes, @SuppressWarnings("unused") int encoding) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
+    @Override
+    public Object Rf_mkCharLenCE(byte[] bytes, int encoding) {
+        if (tracer != null) {
+            tracer.Rf_mkCharLenCE(bytes, encoding);
         }
         // TODO: handle encoding properly
-        return new CharSXPWrapper(new String(bytes, StandardCharsets.UTF_8));
+        return CharSXPWrapper.create(new String(bytes, StandardCharsets.UTF_8));
     }
 
-    public static Object Rf_cons(Object car, Object cdr) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_cons", car, cdr);
+    @Override
+    public Object Rf_cons(Object car, Object cdr) {
+        if (tracer != null) {
+            tracer.Rf_cons(car, cdr);
         }
         return RDataFactory.createPairList(car, cdr);
     }
 
-    public static void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
+    @Override
+    public void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
+        if (tracer != null) {
+            tracer.Rf_defineVar(symbolArg, value, envArg);
         }
         REnvironment env = (REnvironment) envArg;
         RSymbol name = (RSymbol) symbolArg;
@@ -296,33 +284,39 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object R_do_MAKE_CLASS(String clazz) {
+    @Override
+    public Object R_do_MAKE_CLASS(String clazz) {
+        if (tracer != null) {
+            tracer.R_do_MAKE_CLASS(clazz);
+        }
         String name = "getClass";
         RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
         return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz);
     }
 
-    public static Object Rf_findVar(Object symbolArg, Object envArg) {
-        // WARNING: argument order reversed from Rf_findVarInFrame!
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
+    @Override
+    public Object Rf_findVar(Object symbolArg, Object envArg) {
+        if (tracer != null) {
+            tracer.Rf_findVar(symbolArg, envArg);
         }
         return findVarInFrameHelper(envArg, symbolArg, true);
     }
 
-    public static Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findVarInFrame", envArg, symbolArg);
+    @Override
+    public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
+        if (tracer != null) {
+            tracer.Rf_findVarInFrame(envArg, symbolArg);
         }
         return findVarInFrameHelper(envArg, symbolArg, false);
     }
 
-    public static Object Rf_findVarInFrame3(Object envArg, Object symbolArg, @SuppressWarnings("unused") int doGet) {
+    @Override
+    public Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet) {
+        if (tracer != null) {
+            tracer.Rf_findVarInFrame3(envArg, symbolArg, doGet);
+        }
         // GNU R has code for IS_USER_DATBASE that uses doGet
         // This is a lookup in the single environment (envArg) only, i.e. inherits=false
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
-        }
         return findVarInFrameHelper(envArg, symbolArg, false);
     }
 
@@ -349,9 +343,10 @@ public class CallRFFIHelper {
         return RUnboundValue.instance;
     }
 
-    public static Object Rf_getAttrib(Object obj, Object name) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
+    @Override
+    public Object Rf_getAttrib(Object obj, Object name) {
+        if (tracer != null) {
+            tracer.Rf_getAttrib(obj, name);
         }
         Object result = RNull.instance;
         if (obj instanceof RAttributable) {
@@ -368,9 +363,10 @@ public class CallRFFIHelper {
         return result;
     }
 
-    public static void Rf_setAttrib(Object obj, Object name, Object val) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_setAttrib", obj, name, val);
+    @Override
+    public void Rf_setAttrib(Object obj, Object name, Object val) {
+        if (tracer != null) {
+            tracer.Rf_setAttrib(obj, name, val);
         }
         if (obj instanceof RAttributable) {
             RAttributable attrObj = (RAttributable) obj;
@@ -415,9 +411,10 @@ public class CallRFFIHelper {
         return result;
     }
 
-    public static int Rf_inherits(Object x, String clazz) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
+    @Override
+    public int Rf_inherits(Object x, String clazz) {
+        if (tracer != null) {
+            tracer.Rf_inherits(x, clazz);
         }
         int result = 0;
         RStringVector hierarchy = getClassHr(x);
@@ -429,38 +426,43 @@ public class CallRFFIHelper {
         return result;
     }
 
-    public static Object Rf_install(String name) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_install", name);
+    @Override
+    public Object Rf_install(String name) {
+        if (tracer != null) {
+            tracer.Rf_install(name);
         }
         return RDataFactory.createSymbolInterned(name);
     }
 
-    public static Object Rf_lengthgets(Object x, int newSize) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
+    @Override
+    public Object Rf_lengthgets(Object x, int newSize) {
+        if (tracer != null) {
+            tracer.Rf_lengthgets(x, newSize);
         }
         RAbstractVector vec = (RAbstractVector) RRuntime.asAbstractVector(x);
         return vec.resize(newSize);
     }
 
-    public static int Rf_isString(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_isString", x);
+    @Override
+    public int Rf_isString(Object x) {
+        if (tracer != null) {
+            tracer.Rf_isString(x);
         }
         return RRuntime.checkType(x, RType.Character) ? 1 : 0;
     }
 
-    public static int Rf_isNull(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_isNull", x);
+    @Override
+    public int Rf_isNull(Object x) {
+        if (tracer != null) {
+            tracer.Rf_isNull(x);
         }
         return x == RNull.instance ? 1 : 0;
     }
 
-    public static Object Rf_PairToVectorList(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
+    @Override
+    public Object Rf_PairToVectorList(Object x) {
+        if (tracer != null) {
+            tracer.Rf_PairToVectorList(x);
         }
         if (x == RNull.instance) {
             return RDataFactory.createList();
@@ -469,30 +471,34 @@ public class CallRFFIHelper {
         return pl.toRList();
     }
 
-    public static void Rf_error(String msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_error", msg);
+    @Override
+    public void Rf_error(String msg) {
+        if (tracer != null) {
+            tracer.Rf_error(msg);
         }
         throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
-    public static void Rf_warning(String msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_warning", msg);
+    @Override
+    public void Rf_warning(String msg) {
+        if (tracer != null) {
+            tracer.Rf_warning(msg);
         }
         RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
-    public static void Rf_warningcall(Object call, String msg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
+    @Override
+    public void Rf_warningcall(Object call, String msg) {
+        if (tracer != null) {
+            tracer.Rf_warningcall(call, msg);
         }
         RErrorHandling.warningcallRFFI(call, msg);
     }
 
-    public static Object Rf_allocateVector(int mode, int n) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
+    @Override
+    public Object Rf_allocateVector(int mode, int n) {
+        if (tracer != null) {
+            tracer.Rf_allocateVector(mode, n);
         }
         SEXPTYPE type = SEXPTYPE.mapInt(mode);
         if (n < 0) {
@@ -521,9 +527,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object Rf_allocateArray(int mode, Object dimsObj) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
+    @Override
+    public Object Rf_allocateArray(int mode, Object dimsObj) {
+        if (tracer != null) {
+            tracer.Rf_allocateArray(mode, dimsObj);
         }
         RIntVector dims = (RIntVector) dimsObj;
         int n = 1;
@@ -539,9 +546,10 @@ public class CallRFFIHelper {
 
     }
 
-    public static Object Rf_allocateMatrix(int mode, int nrow, int ncol) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
+    @Override
+    public Object Rf_allocateMatrix(int mode, int nrow, int ncol) {
+        if (tracer != null) {
+            tracer.Rf_allocateMatrix(mode, ncol, nrow);
         }
         SEXPTYPE type = SEXPTYPE.mapInt(mode);
         if (nrow < 0 || ncol < 0) {
@@ -565,23 +573,26 @@ public class CallRFFIHelper {
         }
     }
 
-    public static int Rf_nrows(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_nrows", x);
+    @Override
+    public int Rf_nrows(Object x) {
+        if (tracer != null) {
+            tracer.Rf_nrows(x);
         }
         return RRuntime.nrows(x);
     }
 
-    public static int Rf_ncols(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_ncols", x);
+    @Override
+    public int Rf_ncols(Object x) {
+        if (tracer != null) {
+            tracer.Rf_ncols(x);
         }
         return RRuntime.ncols(x);
     }
 
-    public static int LENGTH(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("LENGTH", x);
+    @Override
+    public int LENGTH(Object x) {
+        if (tracer != null) {
+            tracer.LENGTH(x);
         }
         if (x instanceof RAbstractContainer) {
             return ((RAbstractContainer) x).getLength();
@@ -596,26 +607,29 @@ public class CallRFFIHelper {
         }
     }
 
-    public static void SET_STRING_ELT(Object x, int i, Object v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
+    @Override
+    public void SET_STRING_ELT(Object x, int i, Object v) {
+        if (tracer != null) {
+            tracer.SET_STRING_ELT(x, i, v);
         }
         RStringVector vector = guaranteeInstanceOf(x, RStringVector.class);
         CharSXPWrapper element = guaranteeInstanceOf(v, CharSXPWrapper.class);
         vector.setElement(i, element.getContents());
     }
 
-    public static void SET_VECTOR_ELT(Object x, int i, Object v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
+    @Override
+    public void SET_VECTOR_ELT(Object x, int i, Object v) {
+        if (tracer != null) {
+            tracer.SET_VECTOR_ELT(x, i, v);
         }
         RList list = guaranteeInstanceOf(x, RList.class);
         list.setElement(i, v);
     }
 
-    public static byte[] RAW(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("RAW", x);
+    @Override
+    public Object RAW(Object x) {
+        if (tracer != null) {
+            tracer.RAW(x);
         }
         if (x instanceof RRawVector) {
             return ((RRawVector) x).getDataWithoutCopying();
@@ -626,9 +640,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static byte[] LOGICAL(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("LOGICAL", x);
+    @Override
+    public Object LOGICAL(Object x) {
+        if (tracer != null) {
+            tracer.LOGICAL(x);
         }
         if (x instanceof RLogicalVector) {
             return ((RLogicalVector) x).getDataWithoutCopying();
@@ -639,9 +654,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static int[] INTEGER(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("INTEGER", x);
+    @Override
+    public Object INTEGER(Object x) {
+        if (tracer != null) {
+            tracer.INTEGER(x);
         }
         if (x instanceof RIntVector) {
             return ((RIntVector) x).getDataWithoutCopying();
@@ -662,9 +678,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static double[] REAL(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("REAL", x);
+    @Override
+    public Object REAL(Object x) {
+        if (tracer != null) {
+            tracer.REAL(x);
         }
         if (x instanceof RDoubleVector) {
             return ((RDoubleVector) x).getDataWithoutCopying();
@@ -676,33 +693,19 @@ public class CallRFFIHelper {
         }
     }
 
-    /**
-     * Called to possibly update the "complete" status on {@code x}. N.B. {@code x} may not be an
-     * object with a concrete {@code setComplete} method, e.g. see {@link #INTEGER(Object)}.
-     */
-    public static void setComplete(Object x, boolean complete) {
-        // only care about concrete vectors
-        if (x instanceof RVector) {
-            ((RVector<?>) x).setComplete(complete);
-        }
-    }
-
-    public static void logObject(Object x) {
-        System.out.println("object " + x);
-        System.out.println("class " + x.getClass());
-    }
-
-    public static Object STRING_ELT(Object x, int i) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("STRING_ELT", x, i);
+    @Override
+    public Object STRING_ELT(Object x, int i) {
+        if (tracer != null) {
+            tracer.STRING_ELT(x, i);
         }
         RAbstractStringVector vector = guaranteeInstanceOf(RRuntime.asAbstractVector(x), RAbstractStringVector.class);
-        return new CharSXPWrapper(vector.getDataAt(i));
+        return CharSXPWrapper.create(vector.getDataAt(i));
     }
 
-    public static Object VECTOR_ELT(Object x, int i) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
+    @Override
+    public Object VECTOR_ELT(Object x, int i) {
+        if (tracer != null) {
+            tracer.VECTOR_ELT(x, i);
         }
         Object vec = x;
         if (vec instanceof RExpression) {
@@ -712,9 +715,10 @@ public class CallRFFIHelper {
         return list.getDataAt(i);
     }
 
-    public static int NAMED(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("NAMED", x);
+    @Override
+    public int NAMED(Object x) {
+        if (tracer != null) {
+            tracer.NAMED(x);
         }
         if (x instanceof RShareable) {
             return ((RShareable) x).isShared() ? 1 : 0;
@@ -723,9 +727,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object SET_TYPEOF_FASTR(Object x, int v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
+    @Override
+    public Object SET_TYPEOF_FASTR(Object x, int v) {
+        if (tracer != null) {
+            tracer.SET_TYPEOF_FASTR(x, v);
         }
         int code = SEXPTYPE.gnuRCodeForObject(x);
         if (code == SEXPTYPE.LISTSXP.code && v == SEXPTYPE.LANGSXP.code) {
@@ -735,9 +740,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static int TYPEOF(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("TYPEOF", x);
+    @Override
+    public int TYPEOF(Object x) {
+        if (tracer != null) {
+            tracer.TYPEOF(x);
         }
         if (x instanceof CharSXPWrapper) {
             return SEXPTYPE.CHARSXP.code;
@@ -746,9 +752,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static int OBJECT(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("OBJECT", x);
+    @Override
+    public int OBJECT(Object x) {
+        if (tracer != null) {
+            tracer.OBJECT(x);
         }
         if (x instanceof RAttributable) {
             return ((RAttributable) x).getAttr(RRuntime.CLASS_ATTR_KEY) == null ? 0 : 1;
@@ -757,9 +764,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object Rf_duplicate(Object x, int deep) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_duplicate", x, deep);
+    @Override
+    public Object Rf_duplicate(Object x, int deep) {
+        if (tracer != null) {
+            tracer.Rf_duplicate(x, deep);
         }
         guarantee(x != null, "unexpected type: null instead of " + x.getClass().getSimpleName());
         guarantee(x instanceof RShareable || x instanceof RIntSequence || x instanceof RExternalPtr,
@@ -773,9 +781,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static int Rf_anyDuplicated(Object x, int fromLast) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
+    @Override
+    public int Rf_anyDuplicated(Object x, int fromLast) {
+        if (tracer != null) {
+            tracer.Rf_anyDuplicated(x, fromLast);
         }
         RAbstractVector vec = (RAbstractVector) x;
         if (vec.getLength() == 0) {
@@ -785,17 +794,19 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object PRINTNAME(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("PRINTNAME", x);
+    @Override
+    public Object PRINTNAME(Object x) {
+        if (tracer != null) {
+            tracer.PRINTNAME(x);
         }
         guaranteeInstanceOf(x, RSymbol.class);
-        return new CharSXPWrapper(((RSymbol) x).getName());
+        return CharSXPWrapper.create(((RSymbol) x).getName());
     }
 
-    public static Object TAG(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("TAG", e);
+    @Override
+    public Object TAG(Object e) {
+        if (tracer != null) {
+            tracer.TAG(e);
         }
         if (e instanceof RPairList) {
             return ((RPairList) e).getTag();
@@ -806,9 +817,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object CAR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CAR", e);
+    @Override
+    public Object CAR(Object e) {
+        if (tracer != null) {
+            tracer.CAR(e);
         }
         guarantee(e != null && (RPairList.class.isInstance(e) || RLanguage.class.isInstance(e)), "CAR only works on pair lists and language objects");
         if (e instanceof RPairList) {
@@ -818,9 +830,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object CDR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CDR", e);
+    @Override
+    public Object CDR(Object e) {
+        if (tracer != null) {
+            tracer.CDR(e);
         }
         if (e instanceof RLanguage) {
             RLanguage lang = (RLanguage) e;
@@ -832,9 +845,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object CADR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CADR", e);
+    @Override
+    public Object CADR(Object e) {
+        if (tracer != null) {
+            tracer.CADR(e);
         }
         guarantee(e != null && (RPairList.class.isInstance(e) || RLanguage.class.isInstance(e)), "CADR only works on pair lists and language objects");
         if (e instanceof RPairList) {
@@ -844,9 +858,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object CADDR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CADDR", e);
+    @Override
+    public Object CADDR(Object e) {
+        if (tracer != null) {
+            tracer.CADDR(e);
         }
         guarantee(e != null && (RPairList.class.isInstance(e) || RLanguage.class.isInstance(e)), "CADDR only works on pair lists and language objects");
         if (e instanceof RPairList) {
@@ -856,9 +871,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object CDDR(Object e) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("CDDR", e);
+    @Override
+    public Object CDDR(Object e) {
+        if (tracer != null) {
+            tracer.CDDR(e);
         }
         if (e instanceof RLanguage) {
             RLanguage lang = (RLanguage) e;
@@ -870,9 +886,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object SET_TAG(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_TAG", x, y);
+    @Override
+    public Object SET_TAG(Object x, Object y) {
+        if (tracer != null) {
+            tracer.SET_TAG(x, y);
         }
         if (x instanceof RPairList) {
             ((RPairList) x).setTag(y);
@@ -884,32 +901,39 @@ public class CallRFFIHelper {
         return y;
     }
 
-    public static Object SETCAR(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SETCAR", x, y);
+    @Override
+    public Object SETCAR(Object x, Object y) {
+        if (tracer != null) {
+            tracer.SETCAR(x, y);
         }
         guaranteeInstanceOf(x, RPairList.class);
         ((RPairList) x).setCar(y);
         return y;
     }
 
-    public static Object SETCDR(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SETCDR", x, y);
+    @Override
+    public Object SETCDR(Object x, Object y) {
+        if (tracer != null) {
+            tracer.SETCDR(x, y);
         }
         guaranteeInstanceOf(x, RPairList.class);
         ((RPairList) x).setCdr(y);
         return y;
     }
 
-    public static Object SETCADR(Object x, Object y) {
+    @Override
+    public Object SETCADR(Object x, Object y) {
+        if (tracer != null) {
+            tracer.SETCADR(x, y);
+        }
         SETCAR(CDR(x), y);
         return y;
     }
 
-    public static Object SYMVALUE(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SYMVALUE", x);
+    @Override
+    public Object SYMVALUE(Object x) {
+        if (tracer != null) {
+            tracer.SYMVALUE(x);
         }
         if (!(x instanceof RSymbol)) {
             throw RInternalError.shouldNotReachHere();
@@ -922,9 +946,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static void SET_SYMVALUE(Object x, Object v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
+    @Override
+    public void SET_SYMVALUE(Object x, Object v) {
+        if (tracer != null) {
+            tracer.SET_SYMVALUE(x, v);
         }
         if (!(x instanceof RSymbol)) {
             throw RInternalError.shouldNotReachHere();
@@ -932,27 +957,29 @@ public class CallRFFIHelper {
         REnvironment.baseEnv().safePut(((RSymbol) x).getName(), v);
     }
 
-    public static int R_BindingIsLocked(Object sym, Object env) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_BindingIsLocked", sym, env);
+    @Override
+    public int R_BindingIsLocked(Object sym, Object env) {
+        if (tracer != null) {
+            tracer.R_BindingIsLocked(sym, env);
         }
         guaranteeInstanceOf(sym, RSymbol.class);
         guaranteeInstanceOf(env, REnvironment.class);
         return ((REnvironment) env).bindingIsLocked(((RSymbol) sym).getName()) ? 1 : 0;
     }
 
-    public static Object R_FindNamespace(Object name) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_FindNamespace", name);
+    @Override
+    public Object R_FindNamespace(Object name) {
+        if (tracer != null) {
+            tracer.R_FindNamespace(name);
         }
         Object result = RContext.getInstance().stateREnvironment.getNamespaceRegistry().get(RRuntime.asString(name));
         return result;
     }
 
-    @TruffleBoundary
-    public static Object Rf_eval(Object expr, Object env) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_eval", expr, env);
+    @Override
+    public Object Rf_eval(Object expr, Object env) {
+        if (tracer != null) {
+            tracer.Rf_eval(expr, env);
         }
         guarantee(env instanceof REnvironment);
         Object result;
@@ -981,9 +1008,10 @@ public class CallRFFIHelper {
         return result;
     }
 
-    public static Object Rf_findfun(Object symbolObj, Object envObj) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
+    @Override
+    public Object Rf_findfun(Object symbolObj, Object envObj) {
+        if (tracer != null) {
+            tracer.Rf_findfun(symbolObj, envObj);
         }
         guarantee(envObj instanceof REnvironment);
         REnvironment env = (REnvironment) envObj;
@@ -999,18 +1027,20 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object Rf_GetOption1(Object tag) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_GetOption1", tag);
+    @Override
+    public Object Rf_GetOption1(Object tag) {
+        if (tracer != null) {
+            tracer.Rf_GetOption1(tag);
         }
         guarantee(tag instanceof RSymbol);
         Object result = RContext.getInstance().stateROptions.getValue(((RSymbol) tag).getName());
         return result;
     }
 
-    public static void Rf_gsetVar(Object symbol, Object value, Object rho) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
+    @Override
+    public void Rf_gsetVar(Object symbol, Object value, Object rho) {
+        if (tracer != null) {
+            tracer.Rf_gsetVar(symbol, value, rho);
         }
         guarantee(symbol instanceof RSymbol);
         REnvironment baseEnv = RContext.getInstance().stateREnvironment.getBaseEnv();
@@ -1022,9 +1052,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static void DUPLICATE_ATTRIB(Object to, Object from) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
+    @Override
+    public void DUPLICATE_ATTRIB(Object to, Object from) {
+        if (tracer != null) {
+            tracer.DUPLICATE_ATTRIB(to, from);
         }
         if (from instanceof RAttributable) {
             guaranteeInstanceOf(to, RAttributable.class);
@@ -1034,9 +1065,10 @@ public class CallRFFIHelper {
         // TODO: copy OBJECT? and S4 attributes
     }
 
-    public static int R_computeIdentical(Object x, Object y, int flags) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
+    @Override
+    public int R_computeIdentical(Object x, Object y, int flags) {
+        if (tracer != null) {
+            tracer.R_computeIdentical(x, y, flags);
         }
         RFunction indenticalBuiltin = RContext.lookupBuiltin("identical");
         Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
@@ -1044,25 +1076,26 @@ public class CallRFFIHelper {
         return (int) res;
     }
 
-    @SuppressWarnings("unused")
-    public static void Rf_copyListMatrix(Object s, Object t, int byrow) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
+    @Override
+    public void Rf_copyListMatrix(Object s, Object t, int byrow) {
+        if (tracer != null) {
+            tracer.Rf_copyListMatrix(s, t, byrow);
         }
         throw unimplemented();
     }
 
-    @SuppressWarnings("unused")
-    public static void Rf_copyMatrix(Object s, Object t, int byrow) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
+    @Override
+    public void Rf_copyMatrix(Object s, Object t, int byrow) {
+        if (tracer != null) {
+            tracer.Rf_copyMatrix(s, t, byrow);
         }
         throw unimplemented();
     }
 
-    public static Object R_tryEval(Object expr, Object env, boolean silent) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
+    @Override
+    public Object R_tryEval(Object expr, Object env, boolean silent) {
+        if (tracer != null) {
+            tracer.R_tryEval(expr, env, silent);
         }
         Object handlerStack = RErrorHandling.getHandlerStack();
         Object restartStack = RErrorHandling.getRestartStack();
@@ -1083,25 +1116,27 @@ public class CallRFFIHelper {
      * a C function is invoked (in the native layer) instead of an R expression. assert: this is
      * ONLY called from R_TopLevelExec prior to calling C function.
      */
-    public static Object resetAndGetErrorHandlerStacks() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_TopLevelExec");
+    @Override
+    public Object R_ToplevelExec() {
+        if (tracer != null) {
+            tracer.R_ToplevelExec();
         }
         return RErrorHandling.resetAndGetHandlerStacks();
     }
 
     /**
-     * Helper function for {@code R_TopLevelExec}, see {@link #resetAndGetErrorHandlerStacks()},
-     * called after C function returns.
+     * Helper function for {@code R_TopLevelExec}, see {@link #R_ToplevelExec()}, called after C
+     * function returns.
      */
-    public static void restoreErrorHandlerStacks(Object stacks) {
+    public void R_ToplevelExecRestoreErrorHandlerStacks(Object stacks) {
         RErrorHandling.HandlerStacks handlerStacks = guaranteeInstanceOf(stacks, RErrorHandling.HandlerStacks.class);
         RErrorHandling.restoreHandlerStacks(handlerStacks);
     }
 
-    public static int RDEBUG(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("RDEBUG", x);
+    @Override
+    public int RDEBUG(Object x) {
+        if (tracer != null) {
+            tracer.RDEBUG(x);
         }
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         if (env instanceof REnvironment.Function) {
@@ -1113,9 +1148,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static void SET_RDEBUG(Object x, int v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
+    @Override
+    public void SET_RDEBUG(Object x, int v) {
+        if (tracer != null) {
+            tracer.SET_RDEBUG(x, v);
         }
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         if (env instanceof REnvironment.Function) {
@@ -1129,27 +1165,30 @@ public class CallRFFIHelper {
         }
     }
 
-    public static int RSTEP(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("RSTEP", x);
+    @Override
+    public int RSTEP(Object x) {
+        if (tracer != null) {
+            tracer.RSTEP(x);
         }
         @SuppressWarnings("unused")
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         throw RInternalError.unimplemented("RSTEP");
     }
 
-    public static void SET_RSTEP(Object x, int v) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("SET_RSTEP", x, v);
+    @Override
+    public void SET_RSTEP(Object x, int v) {
+        if (tracer != null) {
+            tracer.SET_RSTEP(x, v);
         }
         @SuppressWarnings("unused")
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         throw RInternalError.unimplemented("SET_RSTEP");
     }
 
-    public static Object ENCLOS(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("ENCLOS", x);
+    @Override
+    public Object ENCLOS(Object x) {
+        if (tracer != null) {
+            tracer.ENCLOS(x);
         }
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         Object result = env.getParent();
@@ -1159,35 +1198,19 @@ public class CallRFFIHelper {
         return result;
     }
 
-    public static Object PRVALUE(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("PRVALUE", x);
+    @Override
+    public Object PRVALUE(Object x) {
+        if (tracer != null) {
+            tracer.PRVALUE(x);
         }
         RPromise p = guaranteeInstanceOf(x, RPromise.class);
         return p.isEvaluated() ? p.getValue() : RUnboundValue.instance;
     }
 
-    private enum ParseStatus {
-        PARSE_NULL,
-        PARSE_OK,
-        PARSE_INCOMPLETE,
-        PARSE_ERROR,
-        PARSE_EOF
-    }
-
-    private static class ParseResult {
-        @SuppressWarnings("unused") private final int parseStatus;
-        @SuppressWarnings("unused") private final Object expr;
-
-        private ParseResult(int parseStatus, Object expr) {
-            this.parseStatus = parseStatus;
-            this.expr = expr;
-        }
-    }
-
-    public static Object R_ParseVector(Object text, int n, Object srcFile) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ParseVector", text, n, srcFile);
+    @Override
+    public Object R_ParseVector(Object text, int n, Object srcFile) {
+        if (tracer != null) {
+            tracer.R_ParseVector(text, n, srcFile);
         }
         // TODO general case
         assert n == 1;
@@ -1206,9 +1229,10 @@ public class CallRFFIHelper {
 
     }
 
-    public static Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_lsInternal3", envArg, allArg, sortedArg);
+    @Override
+    public Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
+        if (tracer != null) {
+            tracer.R_lsInternal3(envArg, allArg, sortedArg);
         }
         boolean sorted = sortedArg != 0;
         boolean all = allArg != 0;
@@ -1216,29 +1240,28 @@ public class CallRFFIHelper {
         return env.ls(all, null, sorted);
     }
 
-    public static String R_HomeDir() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_HomeDir");
+    @Override
+    public String R_HomeDir() {
+        if (tracer != null) {
+            tracer.R_HomeDir();
         }
         return REnvVars.rHome();
     }
 
-    @SuppressWarnings("unused")
-    private static void R_CleanUp(int sa, int status, int runlast) {
+    @Override
+    public void R_CleanUp(int sa, int status, int runlast) {
+        if (tracer != null) {
+            tracer.R_CleanUp(sa, status, runlast);
+        }
         RCleanUp.stdCleanUp(SA_TYPE.values()[sa], status, runlast != 0);
     }
 
-    // Checkstyle: resume method name check
-
-    public static Object validate(Object x) {
-        return x;
-    }
-
-    public static Object getGlobalContext() {
-        Utils.warn("Potential memory leak (global context object)");
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getGlobalContext");
+    @Override
+    public Object R_GlobalContext() {
+        if (tracer != null) {
+            tracer.R_GlobalContext();
         }
+        Utils.warn("Potential memory leak (global context object)");
         Frame frame = Utils.getActualCurrentFrame();
         if (frame == null) {
             return RCaller.topLevel;
@@ -1250,80 +1273,94 @@ public class CallRFFIHelper {
         return rCaller == null ? RCaller.topLevel : rCaller;
     }
 
-    public static Object getGlobalEnv() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getGlobalEnv");
+    @Override
+    public Object R_GlobalEnv() {
+        if (tracer != null) {
+            tracer.R_GlobalEnv();
         }
         return RContext.getInstance().stateREnvironment.getGlobalEnv();
     }
 
-    public static Object getBaseEnv() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getBaseEnv");
+    @Override
+    public Object R_BaseEnv() {
+        if (tracer != null) {
+            tracer.R_BaseEnv();
         }
         return RContext.getInstance().stateREnvironment.getBaseEnv();
     }
 
-    public static Object getBaseNamespace() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getBaseNamespace");
+    @Override
+    public Object R_BaseNamespace() {
+        if (tracer != null) {
+            tracer.R_BaseNamespace();
         }
         return RContext.getInstance().stateREnvironment.getBaseNamespace();
     }
 
-    public static Object getNamespaceRegistry() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getNamespaceRegistry");
+    @Override
+    public Object R_NamespaceRegistry() {
+        if (tracer != null) {
+            tracer.R_NamespaceRegistry();
         }
         return RContext.getInstance().stateREnvironment.getNamespaceRegistry();
     }
 
-    public static int isInteractive() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("isInteractive");
+    @Override
+    public int isInteractive() {
+        if (tracer != null) {
+            tracer.isInteractive();
         }
         return RContext.getInstance().isInteractive() ? 1 : 0;
     }
 
-    public static int isS4Object(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("isS4Object");
+    @Override
+    public int isS4Object(Object x) {
+        if (tracer != null) {
+            tracer.isS4Object(x);
         }
         return x instanceof RS4Object ? 1 : 0;
     }
 
-    public static void printf(String message) {
+    @Override
+    public void Rprintf(String message) {
+        if (tracer != null) {
+            tracer.Rprintf(message);
+        }
         RContext.getInstance().getConsoleHandler().print(message);
     }
 
-    public static void getRNGstate() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getRNGstate");
+    @Override
+    public void GetRNGstate() {
+        if (tracer != null) {
+            tracer.GetRNGstate();
         }
         RRNG.getRNGState();
     }
 
-    public static void putRNGstate() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("putRNGstate");
+    @Override
+    public void PutRNGstate() {
+        if (tracer != null) {
+            tracer.PutRNGstate();
         }
         RRNG.putRNGState();
     }
 
-    public static double unifRand() {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("unifRand");
+    @Override
+    public double unif_rand() {
+        if (tracer != null) {
+            tracer.unif_rand();
         }
         return RRNG.unifRand();
     }
 
     // Checkstyle: stop method name check
 
-    public static Object R_getGlobalFunctionContext() {
-        Utils.warn("Potential memory leak (global function context object)");
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getGlobalFunctionContext");
+    @Override
+    public Object R_getGlobalFunctionContext() {
+        if (tracer != null) {
+            tracer.R_getGlobalFunctionContext();
         }
+        Utils.warn("Potential memory leak (global function context object)");
         Frame frame = Utils.getActualCurrentFrame();
         if (frame == null) {
             return RNull.instance;
@@ -1338,11 +1375,12 @@ public class CallRFFIHelper {
         return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller;
     }
 
-    public static Object R_getParentFunctionContext(Object c) {
-        Utils.warn("Potential memory leak (parent function context object)");
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getParentFunctionContext");
+    @Override
+    public Object R_getParentFunctionContext(Object c) {
+        if (tracer != null) {
+            tracer.R_getParentFunctionContext(c);
         }
+        Utils.warn("Potential memory leak (parent function context object)");
         RCaller currentCaller = guaranteeInstanceOf(c, RCaller.class);
         while (true) {
             currentCaller = currentCaller.getParent();
@@ -1354,9 +1392,10 @@ public class CallRFFIHelper {
         return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller;
     }
 
-    public static Object R_getContextEnv(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getContextEnv", c);
+    @Override
+    public Object R_getContextEnv(Object c) {
+        if (tracer != null) {
+            tracer.R_getContextEnv(c);
         }
         RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
         if (rCaller == RCaller.topLevel) {
@@ -1382,9 +1421,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object R_getContextFun(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getContextEnv", c);
+    @Override
+    public Object R_getContextFun(Object c) {
+        if (tracer != null) {
+            tracer.R_getContextFun(c);
         }
         RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
         if (rCaller == RCaller.topLevel) {
@@ -1410,9 +1450,10 @@ public class CallRFFIHelper {
         }
     }
 
-    public static Object R_getContextCall(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getContextEnv", c);
+    @Override
+    public Object R_getContextCall(Object c) {
+        if (tracer != null) {
+            tracer.R_getContextCall(c);
         }
         RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
         if (rCaller == RCaller.topLevel) {
@@ -1421,9 +1462,10 @@ public class CallRFFIHelper {
         return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller);
     }
 
-    public static Object R_getContextSrcRef(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("getContextSrcRef", c);
+    @Override
+    public Object R_getContextSrcRef(Object c) {
+        if (tracer != null) {
+            tracer.R_getContextSrcRef(c);
         }
         Object o = R_getContextFun(c);
         if (!(o instanceof RFunction)) {
@@ -1438,94 +1480,133 @@ public class CallRFFIHelper {
 
     }
 
-    public static int R_insideBrowser() {
+    @Override
+    public int R_insideBrowser() {
+        if (tracer != null) {
+            tracer.R_insideBrowser();
+        }
         return RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser() ? 1 : 0;
     }
 
-    public static int R_isGlobal(Object c) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("isGlobal", c);
+    @Override
+    public int R_isGlobal(Object c) {
+        if (tracer != null) {
+            tracer.R_isGlobal(c);
         }
         RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
 
         return rCaller == RCaller.topLevel ? 1 : 0;
     }
 
-    public static int R_isEqual(Object x, Object y) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("isEqual", x, y);
+    @Override
+    public int R_isEqual(Object x, Object y) {
+        if (tracer != null) {
+            tracer.R_isEqual(x, y);
         }
         return x == y ? 1 : 0;
     }
 
-    public static Object Rf_classgets(Object x, Object y) {
+    @Override
+    public Object Rf_classgets(Object x, Object y) {
+        if (tracer != null) {
+            tracer.Rf_classgets(x, y);
+        }
         RAbstractVector vector = guaranteeInstanceOf(x, RAbstractVector.class);
         vector.setClassAttr(guaranteeInstanceOf(y, RStringVector.class));
         return RNull.instance;
     }
 
-    public static RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_MakeExternalPtr", addr, tag, prot);
+    @Override
+    public RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
+        if (tracer != null) {
+            tracer.R_MakeExternalPtr(addr, tag, prot);
         }
         return RDataFactory.createExternalPtr(new SymbolHandle(addr), tag, prot);
     }
 
-    public static long R_ExternalPtrAddr(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrAddr", x);
+    @Override
+    public long R_ExternalPtrAddr(Object x) {
+        if (tracer != null) {
+            tracer.R_ExternalPtrAddr(x);
         }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         return p.getAddr().asAddress();
     }
 
-    public static Object R_ExternalPtrTag(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrTag", x);
+    @Override
+    public Object R_ExternalPtrTag(Object x) {
+        if (tracer != null) {
+            tracer.R_ExternalPtrTag(x);
         }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         return p.getTag();
     }
 
-    public static Object R_ExternalPtrProt(Object x) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+    @Override
+    public Object R_ExternalPtrProt(Object x) {
+        if (tracer != null) {
+            tracer.R_ExternalPtrProt(x);
         }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         return p.getProt();
     }
 
-    public static void R_SetExternalPtrAddr(Object x, long addr) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_SetExternalPtrAddr", x);
+    @Override
+    public void R_SetExternalPtrAddr(Object x, long addr) {
+        if (tracer != null) {
+            tracer.R_SetExternalPtrAddr(x, addr);
         }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         p.setAddr(new SymbolHandle(addr));
     }
 
-    public static void R_SetExternalPtrTag(Object x, Object tag) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_SetExternalPtrTag", x);
+    @Override
+    public void R_SetExternalPtrTag(Object x, Object tag) {
+        if (tracer != null) {
+            tracer.R_SetExternalPtrTag(x, tag);
         }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         p.setTag(tag);
     }
 
-    public static void R_SetExternalPtrProt(Object x, Object prot) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+    @Override
+    public void R_SetExternalPtrProt(Object x, Object prot) {
+        if (tracer != null) {
+            tracer.R_SetExternalPtrProt(x, prot);
         }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         p.setProt(prot);
     }
 
-    public static REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
-        if (RFFIUtils.traceEnabled()) {
-            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, name, hashed, initialSize);
+    @Override
+    public REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
+        if (tracer != null) {
+            tracer.R_NewHashedEnv(parent, name, hashed, initialSize);
         }
         REnvironment env = RDataFactory.createNewEnv(name, hashed, initialSize);
         RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
         return env;
     }
 
+    // Implementation specific support
+
+    /**
+     * Called to possibly update the "complete" status on {@code x}. N.B. {@code x} may not be an
+     * object with a concrete {@code setComplete} method, e.g. see {@link #INTEGER(Object)}.
+     */
+    public void setComplete(Object x, boolean complete) {
+        // only care about concrete vectors
+        if (x instanceof RVector) {
+            ((RVector<?>) x).setComplete(complete);
+        }
+    }
+
+    /**
+     * Called when a {@link CharSXPWrapper} is expected and not found.
+     */
+    public void logNotCharSXPWrapper(Object x) {
+        System.out.println("object " + x);
+        System.out.println("class " + x.getClass());
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFIFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9666616f0199f060d9b5b5e9372722362f4d63a
--- /dev/null
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFIFactory.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+public class JavaUpCallsRFFIFactory extends UpCallsRFFIFactory {
+
+    @Override
+    public UpCallsRFFI getUpcallsRFFI() {
+        return new JavaUpCallsRFFI();
+    }
+
+}
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIVariables.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIVariables.java
index 0695d46b3a50b64b9664e158c287d9e44c03bafc..77628a0b8d8b06eba9a99ed0144e89924e0f12a6 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIVariables.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIVariables.java
@@ -29,7 +29,6 @@ import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RUnboundValue;
 import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.ffi.jni.CallRFFIHelper;
 
 public enum RFFIVariables {
     R_Home(REnvVars.rHome()),
@@ -71,7 +70,7 @@ public enum RFFIVariables {
     R_dot_target(RDataFactory.createSymbol(".target")),
     R_SrcrefSymbol(RDataFactory.createSymbol("srcref")),
     R_SrcfileSymbol(RDataFactory.createSymbol("srcfile")),
-    R_NaString(CallRFFIHelper.createCharSXP(RRuntime.STRING_NA)),
+    R_NaString(CharSXPWrapper.create(RRuntime.STRING_NA)),
     R_NaN(Double.NaN),
     R_PosInf(Double.POSITIVE_INFINITY),
     R_NegInf(Double.NEGATIVE_INFINITY),
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java
index 4b79d033cce8889333b8b758dd31c16793a9f3a2..6161b0e4e724a3d1ddf555a888b9a41cf75a3858 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Grid.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.ffi.generic;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.GridRFFI;
@@ -32,46 +33,55 @@ import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public class Generic_Grid implements GridRFFI {
-    private static final class GridProvider {
-        private static GridProvider grid;
-        private static DLL.SymbolHandle initGrid;
-        private static DLL.SymbolHandle killGrid;
+    private static class Generic_GridRFFINode extends GridRFFINode {
+        @Child private CallRFFI.CallRFFINode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode();
 
-        @TruffleBoundary
-        private GridProvider() {
-            System.load(LibPaths.getPackageLibPath("grid"));
-            initGrid = DLL.findSymbol("L_initGrid", "grid", DLL.RegisteredNativeSymbol.any());
-            killGrid = DLL.findSymbol("L_killGrid", "grid", DLL.RegisteredNativeSymbol.any());
-            assert initGrid != DLL.SYMBOL_NOT_FOUND && killGrid != DLL.SYMBOL_NOT_FOUND;
-        }
+        private static final class GridProvider {
+            private static GridProvider grid;
+            private static DLL.SymbolHandle initGrid;
+            private static DLL.SymbolHandle killGrid;
 
-        static GridProvider gridProvider() {
-            if (grid == null) {
-                grid = new GridProvider();
+            @TruffleBoundary
+            private GridProvider() {
+                System.load(LibPaths.getPackageLibPath("grid"));
+                initGrid = DLL.findSymbol("L_initGrid", "grid", DLL.RegisteredNativeSymbol.any());
+                killGrid = DLL.findSymbol("L_killGrid", "grid", DLL.RegisteredNativeSymbol.any());
+                assert initGrid != DLL.SYMBOL_NOT_FOUND && killGrid != DLL.SYMBOL_NOT_FOUND;
+            }
+
+            static GridProvider gridProvider() {
+                if (grid == null) {
+                    grid = new GridProvider();
+                }
+                return grid;
+            }
+
+            @SuppressWarnings("static-method")
+            long getInitGrid() {
+                return initGrid.asAddress();
             }
-            return grid;
-        }
 
-        @SuppressWarnings("static-method")
-        long getInitGrid() {
-            return initGrid.asAddress();
+            @SuppressWarnings("static-method")
+            long getKillGrid() {
+                return killGrid.asAddress();
+            }
         }
 
-        @SuppressWarnings("static-method")
-        long getKillGrid() {
-            return killGrid.asAddress();
+        @Override
+        public Object initGrid(REnvironment gridEvalEnv) {
+            long initGrid = GridProvider.gridProvider().getInitGrid();
+            return callRFFINode.invokeCall(new NativeCallInfo("L_initGrid", new SymbolHandle(initGrid), DLL.findLibrary("grid")), new Object[]{gridEvalEnv});
         }
-    }
 
-    @Override
-    public Object initGrid(REnvironment gridEvalEnv) {
-        long initGrid = GridProvider.gridProvider().getInitGrid();
-        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo("L_initGrid", new SymbolHandle(initGrid), DLL.findLibrary("grid")), new Object[]{gridEvalEnv});
+        @Override
+        public Object killGrid() {
+            long killGrid = GridProvider.gridProvider().getKillGrid();
+            return callRFFINode.invokeCall(new NativeCallInfo("L_killGrid", new SymbolHandle(killGrid), DLL.findLibrary("grid")), new Object[0]);
+        }
     }
 
     @Override
-    public Object killGrid() {
-        long killGrid = GridProvider.gridProvider().getKillGrid();
-        return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo("L_killGrid", new SymbolHandle(killGrid), DLL.findLibrary("grid")), new Object[0]);
+    public GridRFFINode createGridRFFINode() {
+        return new Generic_GridRFFINode();
     }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java
index fedd559f04c17749c46c8744e7379ad5b360870e..6b8a93ca053a86a81ca62bbd16f8e73368633144 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/generic/Generic_Tools.java
@@ -30,6 +30,7 @@ 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.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.LibPaths;
@@ -38,46 +39,59 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
 
 public class Generic_Tools implements ToolsRFFI {
-    private static final class ToolsProvider {
-        private static final String C_PARSE_RD = "C_parseRd";
-        private static ToolsProvider tools;
-        private static DLL.SymbolHandle parseRd;
+    private static class Generic_ToolsRFFINode extends ToolsRFFINode {
+        @Child private CallRFFI.CallRFFINode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode();
 
-        @TruffleBoundary
-        private ToolsProvider() {
-            System.load(LibPaths.getPackageLibPath("tools"));
-            parseRd = DLL.findSymbol(C_PARSE_RD, "tools", DLL.RegisteredNativeSymbol.any());
-            assert parseRd != DLL.SYMBOL_NOT_FOUND;
-        }
+        private static final class ToolsProvider {
+            private static final String C_PARSE_RD = "C_parseRd";
+            private static ToolsProvider tools;
+            private static DLL.SymbolHandle parseRd;
+
+            @TruffleBoundary
+            private ToolsProvider() {
+                System.load(LibPaths.getPackageLibPath("tools"));
+                parseRd = DLL.findSymbol(C_PARSE_RD, "tools", DLL.RegisteredNativeSymbol.any());
+                assert parseRd != DLL.SYMBOL_NOT_FOUND;
+            }
+
+            static ToolsProvider toolsProvider() {
+                if (tools == null) {
+                    tools = new ToolsProvider();
+                }
+                return tools;
+            }
 
-        static ToolsProvider toolsProvider() {
-            if (tools == null) {
-                tools = new ToolsProvider();
+            @SuppressWarnings("static-method")
+            long getParseRd() {
+                return parseRd.asAddress();
             }
-            return tools;
         }
 
-        @SuppressWarnings("static-method")
-        long getParseRd() {
-            return parseRd.asAddress();
+        private static final Semaphore parseRdCritical = new Semaphore(1, false);
+        private NativeCallInfo nativeCallInfo;
+
+        @Override
+        public Object parseRd(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
+                        RLogicalVector warndups) {
+            // The C code is not thread safe.
+            try {
+                parseRdCritical.acquire();
+                long parseRd = ToolsProvider.toolsProvider().getParseRd();
+                if (nativeCallInfo == null) {
+                    nativeCallInfo = new NativeCallInfo("parseRd", new SymbolHandle(parseRd), DLL.findLibrary("tools"));
+                }
+                return callRFFINode.invokeCall(nativeCallInfo,
+                                new Object[]{con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups});
+            } catch (Throwable ex) {
+                throw RInternalError.shouldNotReachHere(ex, "error during Rd parsing");
+            } finally {
+                parseRdCritical.release();
+            }
         }
     }
 
-    private static final Semaphore parseRdCritical = new Semaphore(1, false);
-
     @Override
-    public Object parseRd(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
-                    RLogicalVector warndups) {
-        // The C code is not thread safe.
-        try {
-            parseRdCritical.acquire();
-            long parseRd = ToolsProvider.toolsProvider().getParseRd();
-            return RFFIFactory.getRFFI().getCallRFFI().invokeCall(new NativeCallInfo("parseRd", new SymbolHandle(parseRd), DLL.findLibrary("tools")),
-                            new Object[]{con, srcfile, verbose, fragment, basename, warningCalls, macros, warndups});
-        } catch (Throwable ex) {
-            throw RInternalError.shouldNotReachHere(ex, "error during Rd parsing");
-        } finally {
-            parseRdCritical.release();
-        }
+    public ToolsRFFINode createToolsRFFINode() {
+        return new Generic_ToolsRFFINode();
     }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
index 1928c09f73d4053f518cb777a1c8257b78451ae6..2e7a4c3d7aef66bdb52e71eaafcc12f347d7858e 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
@@ -30,21 +30,27 @@ import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 
 public class JNI_C implements CRFFI {
-
-    /**
-     * This is rather similar to {@link JNI_Call}, except the objects are guaranteed to be native
-     * array types, no upcalls are possible, and no result is returned. However, the receiving
-     * function expects actual native arrays (not SEXPs), so these have to be handled on the JNI
-     * side.
-     */
-    @Override
-    @TruffleBoundary
-    public synchronized void invoke(NativeCallInfo nativeCallInfo, Object[] args) {
-        if (traceEnabled()) {
-            traceDownCall(nativeCallInfo.name, args);
+    private static class JNI_CRFFINode extends CRFFINode {
+        /**
+         * This is rather similar to {@link JNI_Call}, except the objects are guaranteed to be
+         * native array types, no upcalls are possible, and no result is returned. However, the
+         * receiving function expects actual native arrays (not SEXPs), so these have to be handled
+         * on the JNI side.
+         */
+        @Override
+        @TruffleBoundary
+        public synchronized void invoke(NativeCallInfo nativeCallInfo, Object[] args) {
+            if (traceEnabled()) {
+                traceDownCall(nativeCallInfo.name, args);
+            }
+            c(nativeCallInfo.address.asAddress(), args);
         }
-        c(nativeCallInfo.address.asAddress(), args);
     }
 
     private static native void c(long address, Object[] args);
+
+    @Override
+    public CRFFINode createCRFFINode() {
+        return new JNI_CRFFINode();
+    }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
index 8ea6fac033712f9b115c3e191aef0d82a5b8b606..ee4a044a1f19a7438b001314ff4bc6c0a47718fc 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Call.java
@@ -36,6 +36,8 @@ import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFIFactory;
 
 /**
  * The only variety in the signatures for {@code .Call} is the number of arguments. GnuR supports a
@@ -47,12 +49,97 @@ import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
  */
 public class JNI_Call implements CallRFFI {
 
-    protected JNI_Call() {
-        loadLibrary();
+    public static class JNI_CallRFFINode extends CallRFFINode {
+
+        @Override
+        @TruffleBoundary
+        public synchronized Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args) {
+            long address = nativeCallInfo.address.asAddress();
+            Object result = null;
+            if (traceEnabled()) {
+                traceDownCall(nativeCallInfo.name, args);
+            }
+            try {
+                switch (args.length) {
+            // @formatter:off
+            case 0: result = call0(address); break;
+            case 1: result = call1(address, args[0]); break;
+            case 2: result = call2(address, args[0], args[1]); break;
+            case 3: result = call3(address, args[0], args[1], args[2]); break;
+            case 4: result = call4(address, args[0], args[1], args[2], args[3]); break;
+            case 5: result = call5(address, args[0], args[1], args[2], args[3], args[4]); break;
+            case 6: result = call6(address, args[0], args[1], args[2], args[3], args[4], args[5]); break;
+            case 7: result = call7(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
+            case 8: result = call8(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
+            case 9: result = call9(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
+            default:
+                result = call(address, args); break;
+                // @formatter:on
+                }
+                return result;
+            } finally {
+                if (traceEnabled()) {
+                    traceDownCallReturn(nativeCallInfo.name, result);
+                }
+            }
+        }
+
+        @Override
+        @TruffleBoundary
+        public synchronized void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args) {
+            if (traceEnabled()) {
+                traceDownCall(nativeCallInfo.name, args);
+            }
+            long address = nativeCallInfo.address.asAddress();
+            try {
+                switch (args.length) {
+                    case 0:
+                        callVoid0(address);
+                        break;
+                    case 1:
+                        callVoid1(address, args[0]);
+                        break;
+                    default:
+                        throw RInternalError.shouldNotReachHere();
+                }
+            } finally {
+                if (traceEnabled()) {
+                    traceDownCallReturn(nativeCallInfo.name, null);
+                }
+            }
+        }
+
+        @Override
+        public synchronized void setTempDir(String tempDir) {
+            if (traceEnabled()) {
+                traceDownCall("setTempDir", tempDir);
+            }
+            RFFIVariables.setTempDir(tempDir);
+            nativeSetTempDir(tempDir);
+            if (traceEnabled()) {
+                traceDownCallReturn("setTempDir", null);
+            }
+        }
+
+        @Override
+        public synchronized void setInteractive(boolean interactive) {
+            if (traceEnabled()) {
+                traceDownCall("setInteractive", interactive);
+            }
+            nativeSetInteractive(interactive);
+            if (traceEnabled()) {
+                traceDownCallReturn("setInteractive", null);
+            }
+        }
+
     }
 
     private static final boolean ForceRTLDGlobal = false;
 
+    public JNI_Call() {
+        loadLibRLibrary();
+    }
+
     /**
      * Load the {@code libR} library. N.B. this library defines some non-JNI global symbols that are
      * referenced by C code in R packages. Unfortunately, {@link System#load(String)} uses
@@ -64,13 +151,13 @@ public class JNI_Call implements CallRFFI {
      * {@link DLLRFFI#dlopen} is called by {@link DLL#load} which uses JNI!
      */
     @TruffleBoundary
-    private static void loadLibrary() {
+    private static void loadLibRLibrary() {
         String libjnibootPath = LibPaths.getBuiltinLibPath("jniboot");
         System.load(libjnibootPath);
 
         String librffiPath = LibPaths.getBuiltinLibPath("R");
         try {
-            DLL.load(librffiPath, ForceRTLDGlobal, false);
+            DLL.loadLibR(librffiPath, ForceRTLDGlobal, false);
         } catch (DLLException ex) {
             throw new RInternalError(ex, "error while loading " + librffiPath);
         }
@@ -80,7 +167,7 @@ public class JNI_Call implements CallRFFI {
             traceDownCall("initialize");
         }
         try {
-            initialize(RFFIVariables.values());
+            initialize(UpCallsRFFIFactory.getInstance().getUpcallsRFFI(), RFFIVariables.values());
         } finally {
             if (traceEnabled()) {
                 traceDownCallReturn("initialize", null);
@@ -89,40 +176,7 @@ public class JNI_Call implements CallRFFI {
         }
     }
 
-    @Override
-    @TruffleBoundary
-    public synchronized Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args) {
-        long address = nativeCallInfo.address.asAddress();
-        Object result = null;
-        if (traceEnabled()) {
-            traceDownCall(nativeCallInfo.name, args);
-        }
-        try {
-            switch (args.length) {
-            // @formatter:off
-            case 0: result = call0(address); break;
-            case 1: result = call1(address, args[0]); break;
-            case 2: result = call2(address, args[0], args[1]); break;
-            case 3: result = call3(address, args[0], args[1], args[2]); break;
-            case 4: result = call4(address, args[0], args[1], args[2], args[3]); break;
-            case 5: result = call5(address, args[0], args[1], args[2], args[3], args[4]); break;
-            case 6: result = call6(address, args[0], args[1], args[2], args[3], args[4], args[5]); break;
-            case 7: result = call7(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
-            case 8: result = call8(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
-            case 9: result = call9(address, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
-            default:
-                result = call(address, args); break;
-                // @formatter:on
-            }
-            return result;
-        } finally {
-            if (traceEnabled()) {
-                traceDownCallReturn(nativeCallInfo.name, result);
-            }
-        }
-    }
-
-    private static native void initialize(RFFIVariables[] variables);
+    private static native void initialize(UpCallsRFFI upCallRFFI, RFFIVariables[] variables);
 
     private static native void nativeSetTempDir(String tempDir);
 
@@ -150,56 +204,13 @@ public class JNI_Call implements CallRFFI {
 
     private static native Object call9(long address, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9);
 
-    @Override
-    @TruffleBoundary
-    public synchronized void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args) {
-        if (traceEnabled()) {
-            traceDownCall(nativeCallInfo.name, args);
-        }
-        long address = nativeCallInfo.address.asAddress();
-        try {
-            switch (args.length) {
-                case 0:
-                    callVoid0(address);
-                    break;
-                case 1:
-                    callVoid1(address, args[0]);
-                    break;
-                default:
-                    throw RInternalError.shouldNotReachHere();
-            }
-        } finally {
-            if (traceEnabled()) {
-                traceDownCallReturn(nativeCallInfo.name, null);
-            }
-        }
-    }
-
     private static native void callVoid0(long address);
 
     private static native void callVoid1(long address, Object arg1);
 
     @Override
-    public synchronized void setTempDir(String tempDir) {
-        if (traceEnabled()) {
-            traceDownCall("setTempDir", tempDir);
-        }
-        RFFIVariables.setTempDir(tempDir);
-        nativeSetTempDir(tempDir);
-        if (traceEnabled()) {
-            traceDownCallReturn("setTempDir", null);
-        }
-    }
-
-    @Override
-    public synchronized void setInteractive(boolean interactive) {
-        if (traceEnabled()) {
-            traceDownCall("setInteractive", interactive);
-        }
-        nativeSetInteractive(interactive);
-        if (traceEnabled()) {
-            traceDownCallReturn("setInteractive", null);
-        }
+    public CallRFFINode createCallRFFINode() {
+        return new JNI_CallRFFINode();
     }
 
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Lapack.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Lapack.java
index e6d37de0f1f956b90a964530f09c98c501ab724e..7b0a29a0be58fd01a27701d12c1644b9c192da9e 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Lapack.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Lapack.java
@@ -26,77 +26,85 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 
 public class JNI_Lapack implements LapackRFFI {
-    @Override
-    @TruffleBoundary
-    public void ilaver(int[] version) {
-        native_ilaver(version);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int dgeev(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 native_dgeev(jobVL, jobVR, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork) {
-        return native_dgeqp3(m, n, a, lda, jpvt, tau, work, lwork);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int dormqr(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 native_dormqr(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int dtrtrs(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
-        return native_dtrtrs(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int dgetrf(int m, int n, double[] a, int lda, int[] ipiv) {
-        return native_dgetrf(m, n, a, lda, ipiv);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int dpotrf(char uplo, int n, double[] a, int lda) {
-        return native_dpotrf(uplo, n, a, lda);
+    private static class JNI_LapackRFFINode extends LapackRFFINode {
+        @Override
+        @TruffleBoundary
+        public void ilaver(int[] version) {
+            native_ilaver(version);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dgeev(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 native_dgeev(jobVL, jobVR, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork) {
+            return native_dgeqp3(m, n, a, lda, jpvt, tau, work, lwork);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dormqr(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 native_dormqr(side, trans, m, n, k, a, lda, tau, c, ldc, work, lwork);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dtrtrs(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb) {
+            return native_dtrtrs(uplo, trans, diag, n, nrhs, a, lda, b, ldb);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dgetrf(int m, int n, double[] a, int lda, int[] ipiv) {
+            return native_dgetrf(m, n, a, lda, ipiv);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dpotrf(char uplo, int n, double[] a, int lda) {
+            return native_dpotrf(uplo, n, a, lda);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dpstrf(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work) {
+            return native_dpstrf(uplo, n, a, lda, piv, rank, tol, work);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dgesv(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb) {
+            return native_dgesv(n, nrhs, a, lda, ipiv, b, ldb);
+        }
+
+        @Override
+        @TruffleBoundary
+        public double dlange(char norm, int m, int n, double[] a, int lda, double[] work) {
+            return native_dlange(norm, m, n, a, lda, work);
+        }
+
+        @Override
+        @TruffleBoundary
+        public int dgecon(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork) {
+            return native_dgecon(norm, n, a, lda, anorm, rcond, work, iwork);
+        }
+
+        @Override
+        public int dsyevr(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 native_dsyevr(jobz, range, uplo, n, a, lda, vl, vu, il, iu, abstol, m, w, z, ldz, isuppz, work, lwork, iwork, liwork);
+        }
     }
 
     @Override
-    @TruffleBoundary
-    public int dpstrf(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work) {
-        return native_dpstrf(uplo, n, a, lda, piv, rank, tol, work);
+    public LapackRFFINode createLapackRFFINode() {
+        return new JNI_LapackRFFINode();
     }
 
-    @Override
-    @TruffleBoundary
-    public int dgesv(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb) {
-        return native_dgesv(n, nrhs, a, lda, ipiv, b, ldb);
-    }
-
-    @Override
-    @TruffleBoundary
-    public double dlange(char norm, int m, int n, double[] a, int lda, double[] work) {
-        return native_dlange(norm, m, n, a, lda, work);
-    }
-
-    @Override
-    @TruffleBoundary
-    public int dgecon(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork) {
-        return native_dgecon(norm, n, a, lda, anorm, rcond, work, iwork);
-    }
-
-    @Override
-    public int dsyevr(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 native_dsyevr(jobz, range, uplo, n, a, lda, vl, vu, il, iu, abstol, m, w, z, ldz, isuppz, work, lwork, iwork, liwork);
-    }
     // Checkstyle: stop method name
 
     private static native void native_ilaver(int[] version);
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PCRE.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PCRE.java
index dda34a3c1896e369eb8799ffdd981cb4129d8688..7ddfbc4b4367672b27f892e18660395cfce4bac6 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PCRE.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_PCRE.java
@@ -28,45 +28,47 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
 
 public class JNI_PCRE implements PCRERFFI {
-    @Override
-    public long maketables() {
-        return nativeMaketables();
-    }
+    private static class JNI_PCRERFFINode extends PCRERFFINode {
+        @Override
+        public long maketables() {
+            return nativeMaketables();
+        }
 
-    @Override
-    public Result compile(String pattern, int options, long tables) {
-        return nativeCompile(pattern, options, tables);
-    }
+        @Override
+        public Result compile(String pattern, int options, long tables) {
+            return nativeCompile(pattern, options, tables);
+        }
 
-    @Override
-    public int getCaptureCount(long code, long extra) {
-        int res = nativeGetCaptureCount(code, extra);
-        if (res < 0) {
-            CompilerDirectives.transferToInterpreter();
-            throw RError.error(RError.NO_CALLER, RError.Message.WRONG_PCRE_INFO, res);
+        @Override
+        public int getCaptureCount(long code, long extra) {
+            int res = nativeGetCaptureCount(code, extra);
+            if (res < 0) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(RError.NO_CALLER, RError.Message.WRONG_PCRE_INFO, res);
+            }
+            return res;
         }
-        return res;
-    }
 
-    @Override
-    public String[] getCaptureNames(long code, long extra, int captureCount) {
-        String[] ret = new String[captureCount];
-        int res = nativeGetCaptureNames(code, extra, ret);
-        if (res < 0) {
-            CompilerDirectives.transferToInterpreter();
-            throw RError.error(RError.NO_CALLER, RError.Message.WRONG_PCRE_INFO, res);
+        @Override
+        public String[] getCaptureNames(long code, long extra, int captureCount) {
+            String[] ret = new String[captureCount];
+            int res = nativeGetCaptureNames(code, extra, ret);
+            if (res < 0) {
+                CompilerDirectives.transferToInterpreter();
+                throw RError.error(RError.NO_CALLER, RError.Message.WRONG_PCRE_INFO, res);
+            }
+            return ret;
         }
-        return ret;
-    }
 
-    @Override
-    public Result study(long code, int options) {
-        throw RInternalError.unimplemented("pcre_study");
-    }
+        @Override
+        public Result study(long code, int options) {
+            throw RInternalError.unimplemented("pcre_study");
+        }
 
-    @Override
-    public int exec(long code, long extra, String subject, int offset, int options, int[] ovector) {
-        return nativeExec(code, extra, subject, offset, options, ovector, ovector.length);
+        @Override
+        public int exec(long code, long extra, String subject, int offset, int options, int[] ovector) {
+            return nativeExec(code, extra, subject, offset, options, ovector, ovector.length);
+        }
     }
 
     private static native long nativeMaketables();
@@ -80,4 +82,9 @@ public class JNI_PCRE implements PCRERFFI {
     private static native int nativeExec(long code, long extra, String subject, int offset,
                     int options, int[] ovector, int ovectorLen);
 
+    @Override
+    public PCRERFFINode createPCRERFFINode() {
+        return new JNI_PCRERFFINode();
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RAppl.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RAppl.java
index b48a2fa9c113c12f68a2632ee147f1b3c55c4287..995c4d0914be9d4c7a26355f15cf063fcc3a1cfe 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RAppl.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RAppl.java
@@ -26,24 +26,30 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.RApplRFFI;
 
 public class JNI_RAppl implements RApplRFFI {
-    @Override
-    @TruffleBoundary
-    public void dqrdc2(double[] x, int ldx, int n, int p, double tol, int[] rank, double[] qraux, int[] pivot, double[] work) {
-        native_dqrdc2(x, ldx, n, p, tol, rank, qraux, pivot, work);
+    private static class JNI_RApplRFFINode extends RApplRFFINode {
+        @Override
+        @TruffleBoundary
+        public void dqrdc2(double[] x, int ldx, int n, int p, double tol, int[] rank, double[] qraux, int[] pivot, double[] work) {
+            native_dqrdc2(x, ldx, n, p, tol, rank, qraux, pivot, work);
+        }
+
+        @Override
+        @TruffleBoundary
+        public void dqrcf(double[] x, int n, int k, double[] qraux, double[] y, int ny, double[] b, int[] info) {
+            native_dqrcf(x, n, k, qraux, y, ny, b, info);
+        }
+
+        @Override
+        @TruffleBoundary
+        public void dqrls(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) {
+            native_dqrls(x, n, p, y, ny, tol, b, rsd, qty, k, jpvt, qraux, work);
+        }
     }
 
     @Override
-    @TruffleBoundary
-    public void dqrcf(double[] x, int n, int k, double[] qraux, double[] y, int ny, double[] b, int[] info) {
-        native_dqrcf(x, n, k, qraux, y, ny, b, info);
+    public RApplRFFINode createRApplRFFINode() {
+        return new JNI_RApplRFFINode();
     }
-
-    @Override
-    @TruffleBoundary
-    public void dqrls(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) {
-        native_dqrls(x, n, p, y, ny, tol, b, rsd, qty, k, jpvt, qraux, work);
-    }
-
     // Checkstyle: stop method name
 
     private static native void native_dqrdc2(double[] x, int ldx, int n, int p, double tol, int[] rank, double[] qraux, int[] pivot, double[] work);
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java
index 1f0564d90b37b8bb5442bd516e71499ca3157545..0905a092aa7460837a4c2a5129f538687ba18e59 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Stats.java
@@ -29,42 +29,52 @@ import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
 
-// Checkstyle: stop method name
 public class JNI_Stats implements StatsRFFI {
-    @Override
-    @TruffleBoundary
-    public void fft_factor(int n, int[] pmaxf, int[] pmaxp) {
-        native_fft_factor(fft_factor_address().asAddress(), n, pmaxf, pmaxp);
-    }
 
-    @Override
-    @TruffleBoundary
-    public int fft_work(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
-        return native_fft_work(fft_work_address().asAddress(), a, nseg, n, nspn, isn, work, iwork);
-    }
+    public static class JNI_FFTNode extends FFTNode {
+        private SymbolHandle fftWorkAddress;
+        private SymbolHandle fftFactorAddress;
 
-    private SymbolHandle fft_factor_address;
-    private SymbolHandle fft_work_address;
+        @Override
+        @TruffleBoundary
+        public int executeWork(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
+            initialize();
+            return native_fft_work(fftWorkAddress.asAddress(), a, nseg, n, nspn, isn, work, iwork);
+        }
+
+        @Override
+        @TruffleBoundary
+        public void executeFactor(int n, int[] pmaxf, int[] pmaxp) {
+            initialize();
+            native_fft_factor(fftFactorAddress.asAddress(), n, pmaxf, pmaxp);
 
-    private SymbolHandle fft_factor_address() {
-        if (fft_factor_address == null) {
-            DLLInfo dllInfo = DLL.findLibrary("stats");
-            fft_factor_address = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, "fft_factor");
-            assert fft_factor_address != DLL.SYMBOL_NOT_FOUND;
         }
-        return fft_factor_address;
-    }
 
-    private SymbolHandle fft_work_address() {
-        if (fft_work_address == null) {
+        private void initialize() {
+            if (fftWorkAddress == null) {
+                fftWorkAddress = fftAddress("fft_work");
+                fftFactorAddress = fftAddress("fft_factor");
+            }
+        }
+
+        private static SymbolHandle fftAddress(String symbol) {
+            SymbolHandle fftAddress;
             DLLInfo dllInfo = DLL.findLibrary("stats");
-            fft_work_address = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, "fft_work");
-            assert fft_work_address != DLL.SYMBOL_NOT_FOUND;
+            fftAddress = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, symbol);
+            assert fftAddress != DLL.SYMBOL_NOT_FOUND;
+            return fftAddress;
         }
-        return fft_work_address;
+
     }
 
+    @Override
+    public FFTNode createFFTNode() {
+        return new JNI_FFTNode();
+    }
+
+    // Checkstyle: stop method name
     private static native void native_fft_factor(long address, int n, int[] pmaxf, int[] pmaxp);
 
     private static native int native_fft_work(long address, double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork);
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java
index 1387cb869aaaa5c1a8f649187c2aa27cf7d4a24d..e6e374a7981eb37e4eaba2cb5cc281b4a18d3185 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_UserRng.java
@@ -27,36 +27,44 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.UserRngRFFI;
 
 public class JNI_UserRng implements UserRngRFFI {
-    @Override
-    @TruffleBoundary
-    public void init(int seed) {
-        init(Function.Init.getSymbolHandle().asAddress(), seed);
+    private static class JNI_UserRngRFFINode extends UserRngRFFINode {
+        @Override
+        @TruffleBoundary
+        public void init(int seed) {
+            nativeInit(Function.Init.getSymbolHandle().asAddress(), seed);
 
-    }
+        }
 
-    @Override
-    @TruffleBoundary
-    public double rand() {
-        return rand(Function.Rand.getSymbolHandle().asAddress());
-    }
+        @Override
+        @TruffleBoundary
+        public double rand() {
+            return nativeRand(Function.Rand.getSymbolHandle().asAddress());
+        }
 
-    @Override
-    @TruffleBoundary
-    public int nSeed() {
-        return nSeed(Function.NSeed.getSymbolHandle().asAddress());
+        @Override
+        @TruffleBoundary
+        public int nSeed() {
+            return nativeNSeed(Function.NSeed.getSymbolHandle().asAddress());
+        }
+
+        @Override
+        @TruffleBoundary
+        public void seeds(int[] n) {
+            nativeSeeds(Function.Seedloc.getSymbolHandle().asAddress(), n);
+        }
     }
 
     @Override
-    @TruffleBoundary
-    public void seeds(int[] n) {
-        seeds(Function.Seedloc.getSymbolHandle().asAddress(), n);
+    public UserRngRFFINode createUserRngRFFINode() {
+        return new JNI_UserRngRFFINode();
     }
 
-    private static native void init(long address, int seed);
+    private static native void nativeInit(long address, int seed);
+
+    private static native double nativeRand(long address);
 
-    private static native double rand(long address);
+    private static native int nativeNSeed(long address);
 
-    private static native int nSeed(long address);
+    private static native void nativeSeeds(long address, int[] n);
 
-    private static native void seeds(long address, int[] n);
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/TraceUpCallsAdapter.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/TraceUpCallsAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b6d8aab816bc180e5a361d2e3311c02d40e3749
--- /dev/null
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/TraceUpCallsAdapter.java
@@ -0,0 +1,893 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi.jni;
+
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExternalPtr;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+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.RFFIUtils;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+
+public class TraceUpCallsAdapter implements UpCallsRFFI {
+    @Override
+    public RIntVector Rf_ScalarInteger(int value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
+        }
+        return null;
+    }
+
+    @Override
+    public RLogicalVector Rf_ScalarLogical(int value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
+        }
+        return null;
+    }
+
+    @Override
+    public RDoubleVector Rf_ScalarDouble(double value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
+        }
+        return null;
+    }
+
+    @Override
+    public RStringVector Rf_ScalarString(Object value) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ScalarString", value);
+        }
+        return null;
+    }
+
+    @Override
+    public int Rf_asInteger(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asInteger", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public double Rf_asReal(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asReal", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public int Rf_asLogical(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asLogical", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object Rf_asChar(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_asChar", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_mkCharLenCE(byte[] bytes, int encoding) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_cons(Object car, Object cdr) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_cons", car, cdr);
+        }
+        return null;
+    }
+
+    @Override
+    public void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
+        }
+    }
+
+    @Override
+    public Object R_do_MAKE_CLASS(String clazz) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_do_MAKE_CLASS", clazz);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_findVar(Object symbolArg, Object envArg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findVarInFrame", envArg, symbolArg);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_getAttrib(Object obj, Object name) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
+        }
+        return null;
+    }
+
+    @Override
+    public void Rf_setAttrib(Object obj, Object name, Object val) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_setAttrib", obj, name, val);
+        }
+    }
+
+    @Override
+    public int Rf_inherits(Object x, String clazz) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object Rf_install(String name) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_install", name);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_lengthgets(Object x, int newSize) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
+        }
+        return null;
+    }
+
+    @Override
+    public int Rf_isString(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_isString", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public int Rf_isNull(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_isNull", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object Rf_PairToVectorList(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
+        }
+        return null;
+    }
+
+    @Override
+    public void Rf_error(String msg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_error", msg);
+        }
+    }
+
+    @Override
+    public void Rf_warning(String msg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_warning", msg);
+        }
+    }
+
+    @Override
+    public void Rf_warningcall(Object call, String msg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
+        }
+    }
+
+    @Override
+    public Object Rf_allocateVector(int mode, int n) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_allocateArray(int mode, Object dimsObj) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_allocateMatrix(int mode, int nrow, int ncol) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
+        }
+        return null;
+    }
+
+    @Override
+    public int Rf_nrows(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_nrows", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public int Rf_ncols(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_ncols", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public int LENGTH(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("LENGTH", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public void SET_STRING_ELT(Object x, int i, Object v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
+        }
+    }
+
+    @Override
+    public void SET_VECTOR_ELT(Object x, int i, Object v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
+        }
+    }
+
+    @Override
+    public Object RAW(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("RAW", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object LOGICAL(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("LOGICAL", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object INTEGER(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("INTEGER", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object REAL(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("REAL", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object STRING_ELT(Object x, int i) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("STRING_ELT", x, i);
+        }
+        return null;
+    }
+
+    @Override
+    public Object VECTOR_ELT(Object x, int i) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
+        }
+        return null;
+    }
+
+    @Override
+    public int NAMED(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("NAMED", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object SET_TYPEOF_FASTR(Object x, int v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
+        }
+        return null;
+    }
+
+    @Override
+    public int TYPEOF(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("TYPEOF", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public int OBJECT(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("OBJECT", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object Rf_duplicate(Object x, int deep) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_duplicate", x, deep);
+        }
+        return null;
+    }
+
+    @Override
+    public int Rf_anyDuplicated(Object x, int fromLast) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object PRINTNAME(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("PRINTNAME", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object TAG(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("TAG", e);
+        }
+        return null;
+    }
+
+    @Override
+    public Object CAR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CAR", e);
+        }
+        return null;
+    }
+
+    @Override
+    public Object CDR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CDR", e);
+        }
+        return null;
+    }
+
+    @Override
+    public Object CADR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CADR", e);
+        }
+        return null;
+    }
+
+    @Override
+    public Object CADDR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CADDR", e);
+        }
+        return null;
+    }
+
+    @Override
+    public Object CDDR(Object e) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("CDDR", e);
+        }
+        return null;
+    }
+
+    @Override
+    public Object SET_TAG(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_TAG", x, y);
+        }
+        return null;
+    }
+
+    @Override
+    public Object SETCAR(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SETCAR", x, y);
+        }
+        return null;
+    }
+
+    @Override
+    public Object SETCDR(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SETCDR", x, y);
+        }
+        return null;
+    }
+
+    @Override
+    public Object SETCADR(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SETCADR", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object SYMVALUE(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SYMVALUE", x);
+        }
+        return null;
+    }
+
+    @Override
+    public void SET_SYMVALUE(Object x, Object v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
+        }
+    }
+
+    @Override
+    public int R_BindingIsLocked(Object sym, Object env) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_BindingIsLocked", sym, env);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object R_FindNamespace(Object name) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_FindNamespace", name);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_eval(Object expr, Object env) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_eval", expr, env);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_findfun(Object symbolObj, Object envObj) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
+        }
+        return null;
+    }
+
+    @Override
+    public Object Rf_GetOption1(Object tag) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_GetOption1", tag);
+        }
+        return null;
+    }
+
+    @Override
+    public void Rf_gsetVar(Object symbol, Object value, Object rho) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
+        }
+    }
+
+    @Override
+    public void DUPLICATE_ATTRIB(Object to, Object from) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
+        }
+    }
+
+    @Override
+    public int R_computeIdentical(Object x, Object y, int flags) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
+        }
+        return 0;
+    }
+
+    @Override
+    public void Rf_copyListMatrix(Object s, Object t, int byrow) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
+        }
+    }
+
+    @Override
+    public void Rf_copyMatrix(Object s, Object t, int byrow) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
+        }
+    }
+
+    @Override
+    public Object R_tryEval(Object expr, Object env, boolean silent) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_ToplevelExec() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_TopLevelExec");
+        }
+        return null;
+    }
+
+    @Override
+    public int RDEBUG(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("RDEBUG", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public void SET_RDEBUG(Object x, int v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
+        }
+    }
+
+    @Override
+    public int RSTEP(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("RSTEP", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public void SET_RSTEP(Object x, int v) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("SET_RSTEP", x, v);
+        }
+    }
+
+    @Override
+    public Object ENCLOS(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("ENCLOS", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object PRVALUE(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("PRVALUE", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_ParseVector(Object text, int n, Object srcFile) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ParseVector", text, n, srcFile);
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_lsInternal3", envArg, allArg, sortedArg);
+        }
+        return null;
+    }
+
+    @Override
+    public String R_HomeDir() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_HomeDir");
+        }
+        return null;
+    }
+
+    @Override
+    public void R_CleanUp(int sa, int status, int runlast) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_Cleanup", sa, status, runlast);
+        }
+    }
+
+    @Override
+    public Object R_GlobalContext() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_GlobalContext");
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_GlobalEnv() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_GlobalEnv");
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_BaseEnv() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_BaseEnv");
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_BaseNamespace() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_BaseNamespace");
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_NamespaceRegistry() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_NamespaceRegistry");
+        }
+        return null;
+    }
+
+    @Override
+    public int isInteractive() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("isInteractive");
+        }
+        return 0;
+    }
+
+    @Override
+    public int isS4Object(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("isS4Object");
+        }
+        return 0;
+    }
+
+    @Override
+    public void Rprintf(String message) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rprintf", message);
+        }
+    }
+
+    @Override
+    public void GetRNGstate() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("GetRNGstate");
+        }
+    }
+
+    @Override
+    public void PutRNGstate() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("PutRNGstate");
+        }
+    }
+
+    @Override
+    public double unif_rand() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("unif_rand");
+        }
+        return 0;
+    }
+
+    @Override
+    public Object R_getGlobalFunctionContext() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_getGlobalFunctionContext");
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_getParentFunctionContext(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_getParentFunctionContext");
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_getContextEnv(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_getContextEnv", c);
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_getContextFun(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_getContextFun", c);
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_getContextCall(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_getContextCall", c);
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_getContextSrcRef(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_getContextSrcRef", c);
+        }
+        return null;
+    }
+
+    @Override
+    public int R_insideBrowser() {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_insideBrowser");
+        }
+        return 0;
+    }
+
+    @Override
+    public int R_isGlobal(Object c) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_isGlobal", c);
+        }
+        return 0;
+    }
+
+    @Override
+    public int R_isEqual(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("isEqual", x, y);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object Rf_classgets(Object x, Object y) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("Rf_classgets", x, y);
+        }
+        return null;
+    }
+
+    @Override
+    public RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_MakeExternalPtr", addr, tag, prot);
+        }
+        return null;
+    }
+
+    @Override
+    public long R_ExternalPtrAddr(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrAddr", x);
+        }
+        return 0;
+    }
+
+    @Override
+    public Object R_ExternalPtrTag(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrTag", x);
+        }
+        return null;
+    }
+
+    @Override
+    public Object R_ExternalPtrProt(Object x) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+        }
+        return null;
+    }
+
+    @Override
+    public void R_SetExternalPtrAddr(Object x, long addr) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_SetExternalPtrAddr", x);
+        }
+    }
+
+    @Override
+    public void R_SetExternalPtrTag(Object x, Object tag) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_SetExternalPtrTag", x);
+        }
+    }
+
+    @Override
+    public void R_SetExternalPtrProt(Object x, Object prot) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+        }
+    }
+
+    @Override
+    public REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize) {
+        if (RFFIUtils.traceEnabled()) {
+            RFFIUtils.traceUpCall("R_NewHashedEnv", parent, name, hashed, initialSize);
+        }
+        return null;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
index f5a84fb5c59a96e77b0457446cf562667c2ac246..13475477da4af40a519467e8e5d31948d45e7923 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 60e498c60ee86bacb2f327409f5b0dc46f36c249..9337e810d8a898aa8f6c1257525fdbbbdce62cdb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -594,6 +594,7 @@ public final class RError extends RuntimeException {
         UNIMPLEMENTED_ARG_TYPE("unimplemented argument type (arg %d)"),
         C_SYMBOL_NOT_IN_TABLE("C symbol name \"%s\" not in load table"),
         FORTRAN_SYMBOL_NOT_IN_TABLE("Fortran symbol name \"%s\" not in load table"),
+        SYMBOL_NOT_IN_TABLE("\"%s\" not available for .%s() for package \"%s\""),
         NOT_THAT_MANY_FRAMES("not that many frames on the stack"),
         UNIMPLEMENTED_ARGUMENT_TYPE("unimplemented argument type"),
         MUST_BE_SQUARE_NUMERIC("'%s' must be a square numeric matrix"),
@@ -760,7 +761,9 @@ public final class RError extends RuntimeException {
         GAP_MUST_BE_NON_NEGATIVE("'gap' must be non-negative integer"),
         WRONG_PCRE_INFO("'pcre_fullinfo' returned '%d' "),
         BAD_FUNCTION_EXPR("badly formed function expression"),
-        FIRST_ELEMENT_ONLY("only first element of '%s' argument used");
+        FIRST_ELEMENT_ONLY("only first element of '%s' argument used"),
+        MUST_BE_GE_ONE("'%s' must be of length >= 1"),
+        MORE_THAN_ONE_MATCH("there is more than one match in '%s'");
 
         public final String message;
         final boolean hasArgs;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
index 7a4a01cd501f6eca13e219621a21fff3466dc094..835b3d36e23b921d01ad2515f07ee8173188d363 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime;
 
+import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.runtime.context.Engine;
@@ -90,6 +91,12 @@ public interface RRuntimeASTAccess {
      */
     RLanguage getSyntaxCaller(RCaller rl);
 
+    /**
+     * Gets {@code TruffleRLanguage} avoiding project circularity.
+     */
+    @SuppressWarnings("rawtypes")
+    Class<? extends TruffleLanguage> getTruffleRLanguage();
+
     /**
      * Returns a string for a call as represented by {@code rl}, returned originally by
      * {@link #getSyntaxCaller}.
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index ff6d84758b526a9a736b6bb7afe2e83c2be3fafd..88c9bc23ee170a940db7ad22673a263e0f771b9d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -41,7 +41,6 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
index fe0a57bac502c4d7f5fb31cd1a4cfe03f82e17c7..9ee98c9d78bcde430d2e58bc088703ab50ada1bf 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java
@@ -44,7 +44,7 @@ public enum RType {
     DefunctReal("real", -1),
     DefunctSingle("single", -1),
     ExternalPtr("externalptr", -1),
-    S4Object("s4object", -1),
+    S4Object("S4", -1),
     Connection("connection", -1),
     Dots("...", -1);
 
@@ -160,7 +160,7 @@ public enum RType {
                 return DefunctSingle;
             case "externalptr":
                 return ExternalPtr;
-            case "s4object":
+            case "S4":
                 return S4Object;
             case "connection":
                 return Connection;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java
index 050047c15b04f035d312d4198db3e90ed37d70d7..fcc8f9710fb7126add02d5490531426fe29d5974 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/TempPathName.java
@@ -68,7 +68,7 @@ public class TempPathName {
             } else {
                 Utils.rSuicide("cannot create 'R_TempDir'");
             }
-            RFFIFactory.getRFFI().getCallRFFI().setTempDir(tempDirPath);
+            RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode().setTempDir(tempDirPath);
         }
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
index a0f6d36b867504ad6a268ad5117452ca4f91f07a..b699372ccaae032d19a0777b141c5d47ba662ce7 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
@@ -30,7 +30,6 @@ import java.util.LinkedList;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.object.DynamicObject;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index ee4a98fe34d52fe214e9782ea9bbce56594ea2f5..068f49fbdfadf00ed3caae3e9556fd2ae9680bfb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -76,6 +76,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.RFFIContextStateFactory;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
@@ -447,6 +448,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
     public final LazyDBCache.ContextStateImpl stateLazyDBCache;
     public final InstrumentationState stateInstrumentation;
     public final ContextStateImpl stateInternalCode;
+    public final DLL.ContextStateImpl stateDLL;
     /**
      * RFFI implementation state. Cannot be final as choice of FFI implementation is not made at the
      * time the constructor is called.
@@ -457,7 +459,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
 
     private ContextState[] contextStates() {
         return new ContextState[]{stateREnvVars, stateRProfile, stateROptions, stateREnvironment, stateRErrorHandling, stateRConnection, stateStdConnections, stateRNG, stateRFFI, stateRSerialize,
-                        stateLazyDBCache, stateInstrumentation};
+                        stateLazyDBCache, stateInstrumentation, stateDLL};
     }
 
     public static void setEmbedded() {
@@ -501,8 +503,8 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         this.stateLazyDBCache = LazyDBCache.ContextStateImpl.newContextState();
         this.stateInstrumentation = InstrumentationState.newContextState(instrumenter);
         this.stateInternalCode = ContextStateImpl.newContextState();
+        this.stateDLL = DLL.ContextStateImpl.newContextState();
         this.engine = RContext.getRRuntimeASTAccess().createEngine(this);
-
         state.add(State.CONSTRUCTED);
     }
 
@@ -559,13 +561,14 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         stateRConnection.initialize(this);
         stateStdConnections.initialize(this);
         stateRNG.initialize(this);
-        this.stateRFFI = RFFIContextStateFactory.newContextState().initialize(this);
-
+        stateRFFI = RFFIContextStateFactory.newContextState();
+        // separate in case initialize calls getStateRFFI()!
         stateRFFI.initialize(this);
         stateRSerialize.initialize(this);
         stateLazyDBCache.initialize(this);
         stateInstrumentation.initialize(this);
         stateInternalCode.initialize(this);
+        stateDLL.initialize(this);
         state.add(State.INITIALIZED);
 
         if (!embedded) {
@@ -584,7 +587,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
             this.methodTableDispatchOn = info.getParent().methodTableDispatchOn;
         }
         if (initial && !embedded) {
-            RFFIFactory.getRFFI().getCallRFFI().setInteractive(isInteractive());
+            RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode().setInteractive(isInteractive());
             initialContextInitialized = true;
         }
         return this;
@@ -824,6 +827,11 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         return RContext.getInstance().engine;
     }
 
+    public ContextState getStateRFFI() {
+        assert stateRFFI != null;
+        return stateRFFI;
+    }
+
     public PolyglotEngine getVM() {
         return info.getVM();
     }
@@ -844,6 +852,10 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         return exportedSymbols;
     }
 
+    public void addExportedSymbol(String name, TruffleObject obj) {
+        exportedSymbols.put(name, obj);
+    }
+
     public TimeZone getSystemTimeZone() {
         return info.getSystemTimeZone();
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java
index d05f96d5ec35693c48cbf238b01fdffe6f34d930..d5732acff89aa0c8213f3b1c59fe3220f4b677f3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RForeignAccessFactory.java
@@ -28,7 +28,13 @@ import com.oracle.truffle.r.runtime.data.RTruffleObject;
 
 public interface RForeignAccessFactory {
 
-    ForeignAccess getForeignAccess(RTruffleObject value);
+    /**
+     * Return the appropriate {@link ForeignAccess} instance for {@code obj}.
+     */
+    ForeignAccess getForeignAccess(RTruffleObject obj);
 
+    /**
+     * Return the {@link TruffleLanguage} instance for R. (Project circularity workaround).
+     */
     Class<? extends TruffleLanguage<RContext>> getTruffleLanguage();
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
index 6d1ed9e4e3e8da595a2591307208691b93364e0a..2fcc8fee9eb0465109998dde9517ad8123ffda69 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
@@ -142,7 +142,7 @@ public interface RAttributable extends RTypedValue {
      * initialized and will be just cleared, unless nullify is {@code true}.
      *
      * @param nullify Some implementations can force nullifying attributes instance if this flag is
-     *            set to {@code true}. Nullifying is not guaranteed for al implementations.
+     *            set to {@code true}. Nullifying is not guaranteed for all implementations.
      */
     default void resetAllAttributes(boolean nullify) {
         DynamicObject attributes = getAttributes();
@@ -164,6 +164,10 @@ public interface RAttributable extends RTypedValue {
         return (RStringVector) getAttr(profiles, RRuntime.CLASS_ATTR_KEY);
     }
 
+    default RStringVector getClassAttr() {
+        return (RStringVector) getAttr(RRuntime.CLASS_ATTR_KEY);
+    }
+
     /**
      * Returns {@code true} if and only if the value has a {@code class} attribute added explicitly.
      * When {@code true}, it is possible to call {@link RAttributable#getClassHierarchy()}.
@@ -172,6 +176,10 @@ public interface RAttributable extends RTypedValue {
         return getClassAttr(profiles) != null ? true : false;
     }
 
+    default boolean isObject() {
+        return getClassAttr() != null ? true : false;
+    }
+
     static void copyAttributes(RAttributable obj, DynamicObject attrs) {
         if (attrs == null) {
             return;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
index 70c54ef9df0bf9ac8ab717578d672f8fc221402a..8f35974969087a286e79230a3b7af3788e483ff2 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
@@ -27,7 +27,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.object.DynamicObject;
@@ -59,12 +58,13 @@ public final class RAttributesLayout {
     private static final AttrsLayout NAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY);
     private static final AttrsLayout DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY);
     private static final AttrsLayout DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIMNAMES_ATTR_KEY);
+    private static final AttrsLayout ROWNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.ROWNAMES_ATTR_KEY);
     private static final AttrsLayout NAMES_AND_DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIM_ATTR_KEY);
     private static final AttrsLayout DIM_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY);
     private static final AttrsLayout CLASS_AND_CONNID_ATTRS_LAYOUT = new AttrsLayout(RRuntime.CLASS_ATTR_KEY, RRuntime.CONN_ID_ATTR_KEY);
 
-    public static final AttrsLayout[] LAYOUTS = {EMPTY_ATTRS_LAYOUT, CLASS_ATTRS_LAYOUT, NAMES_ATTRS_LAYOUT, DIM_ATTRS_LAYOUT, DIMNAMES_ATTRS_LAYOUT, NAMES_AND_DIM_ATTRS_LAYOUT,
-                    DIM_AND_DIMNAMES_ATTRS_LAYOUT};
+    public static final AttrsLayout[] LAYOUTS = {EMPTY_ATTRS_LAYOUT, CLASS_ATTRS_LAYOUT, NAMES_ATTRS_LAYOUT, DIM_ATTRS_LAYOUT, DIMNAMES_ATTRS_LAYOUT, ROWNAMES_ATTRS_LAYOUT,
+                    NAMES_AND_DIM_ATTRS_LAYOUT, DIM_AND_DIMNAMES_ATTRS_LAYOUT};
 
     private static final Map<String, ConstantShapesAndProperties> constantShapesAndLocationsForAttribute = new HashMap<>();
 
@@ -114,6 +114,13 @@ public final class RAttributesLayout {
                         new Property[]{
                                         CLASS_AND_CONNID_ATTRS_LAYOUT.properties[0]
                         }));
+        constantShapesAndLocationsForAttribute.put(RRuntime.ROWNAMES_ATTR_KEY, new ConstantShapesAndProperties(
+                        new Shape[]{
+                                        ROWNAMES_ATTRS_LAYOUT.shape
+                        },
+                        new Property[]{
+                                        ROWNAMES_ATTRS_LAYOUT.properties[0]
+                        }));
 
     }
 
@@ -147,6 +154,10 @@ public final class RAttributesLayout {
         return DIMNAMES_ATTRS_LAYOUT.factory.newInstance(dimNames);
     }
 
+    public static DynamicObject createRowNames(Object rowNames) {
+        return ROWNAMES_ATTRS_LAYOUT.factory.newInstance(rowNames);
+    }
+
     public static DynamicObject createNamesAndDim(Object names, Object dim) {
         return NAMES_AND_DIM_ATTRS_LAYOUT.factory.newInstance(names, dim);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
index 94d1d71fb49c3ac82b4b3f74a69a2f5fa3e18356..65d16aef9b115d138c0defe6e90f03ab43125e2b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
@@ -47,14 +47,14 @@ public class RExpression extends RListBase implements RAbstractVector {
 
     @Override
     protected RExpression internalCopy() {
-        return new RExpression(Arrays.copyOf(data, data.length), dimensions, null);
+        return new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null);
     }
 
     @Override
     protected RExpression internalDeepCopy() {
         // TOOD: only used for nested list updates, but still could be made faster (through a
         // separate AST node?)
-        RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), dimensions, null);
+        RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null);
         for (int i = 0; i < listCopy.getLength(); i++) {
             Object el = listCopy.getDataAt(i);
             if (el instanceof RVector) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
index dd1d78c81978adf1ae7cd562a1042a5c9c0e90e1..cd52a76a925b0dc067d7554f1c8ea060c24942f1 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
@@ -196,7 +196,7 @@ public class RLanguage extends RSharingAttributeStorage implements RAbstractCont
     }
 
     @Override
-    public void setNames(RStringVector newNames) {
+    public final void setNames(RStringVector newNames) {
         if (list == null) {
             /* See getNames */
             RContext.getRRuntimeASTAccess().setNames(this, newNames);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
index dd97f6ea0d42c018c7089d82c5b38b1a1609dddd..8632d8f56dbb440bf7ed0b0722ea33c34bc0a5cd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
@@ -44,14 +44,14 @@ public final class RList extends RListBase implements RAbstractListVector {
 
     @Override
     protected RList internalCopy() {
-        return new RList(Arrays.copyOf(data, data.length), dimensions, null);
+        return new RList(Arrays.copyOf(data, data.length), getDimensions(), null);
     }
 
     @Override
     protected RList internalDeepCopy() {
         // TOOD: only used for nested list updates, but still could be made faster (through a
         // separate AST node?)
-        RList listCopy = new RList(Arrays.copyOf(data, data.length), dimensions, null);
+        RList listCopy = new RList(Arrays.copyOf(data, data.length), getDimensions(), null);
         for (int i = 0; i < listCopy.getLength(); i++) {
             Object el = listCopy.getDataAt(i);
             if (el instanceof RVector) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
index 4ed316e9098910dadca1a832ced61ce207fdfee0..537d54d73051c4026054cb467d2661f4b271bf06 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
@@ -146,6 +146,7 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
 
     @TruffleBoundary
     public final Object getNameAt(int index) {
+        RStringVector names = getNamesFromAttrs();
         if (names != null && names != null) {
             String name = names.getDataAt(index);
             if (name == RRuntime.STRING_NA) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
index fabe9e5c925816dc58e278f0f2cd4aef95f55b2b..4b514edb83a7774ebb4e417fa35b4ab3373beb86 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
@@ -329,7 +329,7 @@ public class RPairList extends RSharingAttributeStorage implements RAbstractCont
     }
 
     @Override
-    public void setNames(RStringVector newNames) {
+    public final void setNames(RStringVector newNames) {
         Object p = this;
         for (int i = 0; i < newNames.getLength() && !isNull(p); i++) {
             RPairList pList = (RPairList) p;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java
index a18f274d43736e0c7e9936de1eaa8d6adf0aa544..138c53d05712073d0e6941b8a566ef0c2db40e20 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java
@@ -22,10 +22,10 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
-import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.closures.RClosures;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -100,8 +100,7 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector {
 
     @Override
     public String toString() {
-        CompilerAsserts.neverPartOfCompilation();
-        return String.format("%02x", value);
+        return Utils.stringFormat("%02x", value);
     }
 
     public static RRaw valueOf(byte value) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index 4d9c43afdf1371f48b3e288e73d3c4bd153d17de..310bde8f45d7ac97bb6a82e9f6275a0cf11847a2 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -33,7 +33,6 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.SuppressFBWarnings;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -60,18 +59,10 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     private static final RStringVector implicitClassHeaderMatrix = RDataFactory.createStringVector(new String[]{RType.Matrix.getName()}, true);
 
     protected boolean complete; // "complete" means: does not contain NAs
-    protected int[] dimensions;
-    protected RStringVector names;
-    private RList dimNames;
-    // cache rownames for data frames as they are accessed at every data frame access
-    private Object rowNames;
 
     protected RVector(boolean complete, int length, int[] dimensions, RStringVector names) {
         this.complete = complete;
-        this.dimensions = dimensions;
         assert names != this;
-        this.names = names;
-        this.rowNames = RNull.instance;
         if (names != null) {
             // since this constructor is for internal use only, the assertion shouldn't fail
             assert names.getLength() == length : "size mismatch: " + names.getLength() + " vs. " + length;
@@ -85,7 +76,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
                     // one-dimensional arrays do not have names, only dimnames with one value
                     RList newDimNames = RDataFactory.createList(new Object[]{names});
                     initAttributes(RAttributesLayout.createDimAndDimNames(dimensionsVector, newDimNames));
-                    this.dimNames = newDimNames;
                 }
             }
         } else {
@@ -95,6 +85,39 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         }
     }
 
+    private int[] getDimensionsFromAttrs() {
+        if (attributes == null) {
+            return null;
+        } else {
+            RIntVector dims = (RIntVector) attributes.get(RRuntime.DIM_ATTR_KEY);
+            return dims == null ? null : dims.getInternalStore();
+        }
+    }
+
+    private RList getDimNamesFromAttrs() {
+        if (attributes == null) {
+            return null;
+        } else {
+            return (RList) attributes.get(RRuntime.DIMNAMES_ATTR_KEY);
+        }
+    }
+
+    private Object getRowNamesFromAttrs() {
+        if (attributes == null) {
+            return null;
+        } else {
+            return attributes.get(RRuntime.ROWNAMES_ATTR_KEY);
+        }
+    }
+
+    protected final RStringVector getNamesFromAttrs() {
+        if (attributes == null) {
+            return null;
+        } else {
+            return (RStringVector) attributes.get(RRuntime.NAMES_ATTR_KEY);
+        }
+    }
+
     /**
      * Intended for external calls where a mutable copy is needed.
      */
@@ -127,36 +150,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     }
 
     public final int[] getInternalDimensions() {
-        return dimensions;
-    }
-
-    public final void setInternalDimensions(int[] newDimensions) {
-        dimensions = newDimensions;
-    }
-
-    public final RStringVector getInternalNames() {
-        return names;
-    }
-
-    public final void setInternalNames(RStringVector newNames) {
-        assert newNames != this;
-        names = newNames;
-    }
-
-    public final RList getInternalDimNames() {
-        return dimNames;
-    }
-
-    public final void setInternalDimNames(RList newDimNames) {
-        dimNames = newDimNames;
-    }
-
-    public final Object getInternalRowNames() {
-        return rowNames;
-    }
-
-    public final void setInternalRowNames(Object newRowNames) {
-        rowNames = newRowNames;
+        return getDimensionsFromAttrs();
     }
 
     @Override
@@ -179,7 +173,9 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         if (attrProfiles.attrNullProfile(attributes == null)) {
             return null;
         } else {
+            RStringVector names = getNamesFromAttrs();
             if (attrProfiles.attrNullNamesProfile(names == null)) {
+                RList dimNames = getDimNames();
                 if (dimNames != null && dimNames.getLength() == 1) {
                     return (RStringVector) dimNames.getDataAt(0);
                 } else {
@@ -196,7 +192,9 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
      * performance-critical)
      */
     public final RStringVector getNames() {
+        RStringVector names = getNamesFromAttrs();
         if (names == null) {
+            RList dimNames = getDimNames();
             if (dimNames != null && dimNames.getLength() == 1) {
                 return (RStringVector) dimNames.getDataAt(0);
             } else {
@@ -212,6 +210,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         if (getNames(attrProfiles) == null) {
             return -1;
         }
+        RStringVector names = getNamesFromAttrs();
         for (int i = 0; i < names.getLength(); i++) {
             if (names.getDataAt(i).equals(name)) {
                 return i;
@@ -232,6 +231,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         }
         boolean oneMatch = false;
         int match = -1;
+        RStringVector names = getNamesFromAttrs();
         for (int i = 0; i < names.getLength(); i++) {
             if (names.getDataAt(i).startsWith(name)) {
                 if (oneMatch) {
@@ -339,7 +339,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             putAttribute(RRuntime.NAMES_ATTR_KEY, newNames);
         }
         assert newNames != this;
-        this.names = newNames;
     }
 
     @Override
@@ -354,22 +353,20 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             // whether it's one dimensional array or not, assigning null always removes the "names"
             // attribute
             removeAttributeMapping(RRuntime.NAMES_ATTR_KEY);
-            this.names = null;
         } else if (newNames != null) {
             if (newNames.getLength() > this.getLength()) {
                 throw RError.error(invokingNode, RError.Message.ATTRIBUTE_VECTOR_SAME_LENGTH, RRuntime.NAMES_ATTR_KEY, newNames.getLength(), this.getLength());
             }
-            if (this.dimensions != null && dimensions.length == 1) {
+            int[] dimensions = getDimensionsFromAttrs();
+            if (dimensions != null && dimensions.length == 1) {
                 // for one dimensional array, "names" is really "dimnames[[1]]" (see R documentation
                 // for "names" function)
                 RList newDimNames = RDataFactory.createList(new Object[]{newNames});
                 newDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
                 putAttribute(RRuntime.DIMNAMES_ATTR_KEY, newDimNames);
-                this.dimNames = newDimNames;
             } else {
                 putAttribute(RRuntime.NAMES_ATTR_KEY, newNames);
                 assert newNames != this;
-                this.names = newNames;
             }
         }
     }
@@ -380,7 +377,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     }
 
     public final RList getDimNames() {
-        return dimNames;
+        return getDimNamesFromAttrs();
     }
 
     /**
@@ -394,7 +391,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         } else {
             putAttribute(RRuntime.DIMNAMES_ATTR_KEY, newDimNames);
         }
-        this.dimNames = newDimNames;
     }
 
     @Override
@@ -407,8 +403,8 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     private void setDimNames(RList newDimNames, RBaseNode invokingNode) {
         if (attributes != null && newDimNames == null) {
             removeAttributeMapping(RRuntime.DIMNAMES_ATTR_KEY);
-            this.dimNames = null;
         } else if (newDimNames != null) {
+            int[] dimensions = getDimensionsFromAttrs();
             if (dimensions == null) {
                 throw RError.error(invokingNode, RError.Message.DIMNAMES_NONARRAY);
             }
@@ -445,7 +441,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             }
             putAttribute(RRuntime.DIMNAMES_ATTR_KEY, resDimNames);
             resDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
-            this.dimNames = resDimNames;
         }
     }
 
@@ -455,17 +450,16 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     }
 
     public final Object getRowNames() {
-        return rowNames;
+        Object rn = getRowNamesFromAttrs();
+        return rn == null ? RNull.instance : rn;
     }
 
     @Override
     public final void setRowNames(RAbstractVector newRowNames) {
         if (newRowNames == null) {
             removeAttributeMapping(RRuntime.ROWNAMES_ATTR_KEY);
-            this.rowNames = RNull.instance;
         } else {
             putAttribute(RRuntime.ROWNAMES_ATTR_KEY, newRowNames);
-            this.rowNames = newRowNames;
         }
     }
 
@@ -476,22 +470,36 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     @Override
     public final boolean hasDimensions() {
-        return dimensions != null;
+        return attributes == null ? false : attributes.containsKey(RRuntime.DIM_ATTR_KEY);
+    }
+
+    public final boolean hasDimNames() {
+        return attributes == null ? false : attributes.containsKey(RRuntime.DIMNAMES_ATTR_KEY);
+    }
+
+    public final boolean hasRowNames() {
+        return attributes == null ? false : attributes.containsKey(RRuntime.ROWNAMES_ATTR_KEY);
+    }
+
+    public final boolean hasNames() {
+        return attributes == null ? false : attributes.containsKey(RRuntime.NAMES_ATTR_KEY);
     }
 
     @Override
     public final boolean isMatrix() {
+        int[] dimensions = getDimensionsFromAttrs();
         return dimensions != null && dimensions.length == 2;
     }
 
     @Override
     public final boolean isArray() {
+        int[] dimensions = getDimensionsFromAttrs();
         return dimensions != null && dimensions.length > 0;
     }
 
     @Override
     public final int[] getDimensions() {
-        return dimensions;
+        return getDimensionsFromAttrs();
     }
 
     /**
@@ -505,7 +513,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         } else {
             putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
         }
-        this.dimensions = newDimensions;
     }
 
     @Override
@@ -521,7 +528,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             verifyDimensions(getLength(), newDimensions, invokingNode);
             putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
         }
-        this.dimensions = newDimensions;
     }
 
     @Override
@@ -533,6 +539,10 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         return setClassAttrInternal(vector, classAttr);
     }
 
+    public abstract class CNode extends RBaseNode {
+
+    }
+
     private static RAbstractContainer setClassAttrInternal(RVector<?> vector, RStringVector classAttr) {
         if (vector.attributes == null && classAttr != null && classAttr.getLength() != 0) {
             vector.initAttributes();
@@ -562,10 +572,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     }
 
     public final void setAttributes(RVector<?> result) {
-        result.names = this.names;
-        result.dimNames = this.dimNames;
-        result.rowNames = this.rowNames;
-        result.dimensions = this.dimensions;
         if (this.attributes != null) {
             result.initAttributes(RAttributesLayout.copy(this.attributes));
         }
@@ -659,21 +665,13 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     public abstract void transferElementSameType(int toIndex, RAbstractVector fromVector, int fromIndex);
 
-    public final RAttributable copyAttributesFrom(RAttributeProfiles attrProfiles, RAbstractContainer vector) {
+    public final RAttributable copyAttributesFrom(RAbstractContainer vector) {
         // it's meant to be used on a "fresh" vector with only dimensions potentially set
-        assert (this.names == null);
-        assert (this.dimNames == null);
-        assert (this.rowNames == RNull.instance);
-        assert (this.dimensions == null);
+        assert (!hasNames());
+        assert (!hasDimNames());
+        assert (!hasRowNames());
+        assert (!hasDimensions());
         assert (this.attributes == null || this.attributes.size() == 0) : this.attributes.size();
-        if (vector.getDimensions() == null || vector.getDimensions().length != 1) {
-            // only assign name attribute if it's not represented as dimnames (as is the case for
-            // one-dimensional array)
-            this.names = vector.getNames(attrProfiles);
-        }
-        this.dimNames = vector.getDimNames(attrProfiles);
-        this.rowNames = vector.getRowNames(attrProfiles);
-        this.dimensions = vector.getDimensions();
         DynamicObject vecAttributes = vector.getAttributes();
         if (vecAttributes != null) {
             initAttributes(RAttributesLayout.copy(vecAttributes));
@@ -687,13 +685,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
      * Internal version without profiles used in a rare (and already slow) case of double-to-int
      * vector conversion when setting class attribute
      */
-    protected final RAttributable copyAttributesFrom(RVector<?> vector) {
-        if (vector.getDimensions() == null || vector.getDimensions().length != 1) {
-            this.names = vector.getNames();
-        }
-        this.dimNames = vector.getDimNames();
-        this.rowNames = vector.getRowNames();
-        this.dimensions = vector.getDimensions();
+    protected final RAttributable copyAttributesFromVector(RVector<?> vector) {
         DynamicObject vecAttributes = vector.getAttributes();
         if (vecAttributes != null) {
             initAttributes(RAttributesLayout.copy(vecAttributes));
@@ -705,9 +697,9 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     public final void copyNamesDimsDimNamesFrom(RAttributeProfiles attrProfiles, RAbstractVector vector, RBaseNode invokingNode) {
         // it's meant to be used on a "fresh" vector with only dimensions potentially set
-        assert (this.names == null);
-        assert (this.dimNames == null);
-        assert (this.dimensions == null);
+        assert (!hasDimNames());
+        assert (!hasDimNames());
+        assert (!hasDimensions());
         assert (this.attributes == null);
         // for some reason, names is copied first, then dims, then dimnames
         if (vector.getDimensions() == null || vector.getDimensions().length != 1) {
@@ -720,7 +712,8 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     }
 
     public final boolean copyNamesFrom(RAttributeProfiles attrProfiles, RAbstractVector vector) {
-        if (this.dimensions == null) {
+        int[] dimensions = getDimensionsFromAttrs();
+        if (dimensions == null) {
             RStringVector vecNames = vector.getNames(attrProfiles);
             if (vecNames != null) {
                 this.setNames(vecNames);
@@ -742,18 +735,13 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     public final RVector<ArrayT> copyRegAttributesFrom(RAbstractContainer vector) {
         DynamicObject orgAttributes = vector.getAttributes();
         if (orgAttributes != null) {
-            Object newRowNames = null;
             for (RAttributesLayout.RAttribute e : RAttributesLayout.asIterable(orgAttributes)) {
                 String name = e.getName();
                 if (name != RRuntime.DIM_ATTR_KEY && name != RRuntime.DIMNAMES_ATTR_KEY && name != RRuntime.NAMES_ATTR_KEY) {
                     Object val = e.getValue();
                     putAttribute(name, val);
-                    if (name == RRuntime.ROWNAMES_ATTR_KEY) {
-                        newRowNames = val;
-                    }
                 }
             }
-            this.rowNames = newRowNames == null ? RNull.instance : newRowNames;
         }
         return this;
     }
@@ -766,7 +754,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     private RVector<ArrayT> resize(int size, boolean resetAll) {
         this.complete &= getLength() >= size;
         RVector<ArrayT> res = this;
-        RStringVector oldNames = res.names;
+        RStringVector oldNames = res.getNamesFromAttrs();
         res = copyResized(size, true);
         if (this.isShared()) {
             assert res.isTemporary();
@@ -775,14 +763,13 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         if (resetAll) {
             resetAllAttributes(oldNames == null);
         } else {
-            res.copyAttributesFrom(this);
+            res.copyAttributesFromVector(this);
             res.setDimensionsNoCheck(null);
             res.setDimNamesNoCheck(null);
         }
         if (oldNames != null) {
             oldNames = oldNames.resizeWithEmpty(size);
             res.putAttribute(RRuntime.NAMES_ATTR_KEY, oldNames);
-            res.names = oldNames;
         }
         return res;
     }
@@ -790,13 +777,10 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     @TruffleBoundary
     public final void resetDimensions(int[] newDimensions) {
         // reset all attributes other than dimensions;
-        this.dimensions = newDimensions;
         // whether we nullify dimensions or re-set them to a different value, names and dimNames
         // must be reset
-        this.names = null;
-        this.dimNames = null;
-        if (this.dimensions != null) {
-            putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(this.dimensions, true));
+        if (newDimensions != null) {
+            putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(newDimensions, true));
         } else {
             // nullifying dimensions does not reset regular attributes
             if (this.attributes != null) {
@@ -809,10 +793,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     @Override
     public final void resetAllAttributes(boolean nullify) {
-        this.dimensions = null;
-        this.names = null;
-        this.dimNames = null;
-        this.rowNames = RNull.instance;
         if (nullify) {
             this.attributes = null;
         } else {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
index 24cdcd702ad4a17447951e0f3aff6fbf9f5267fc..e8f6e117dc99f28a7193e8c03c849a5072386021 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
@@ -22,14 +22,20 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
+
 /**
  * Support for the {.C} and {.Fortran} calls.
  */
 public interface CRFFI {
-    /**
-     * Invoke the native method identified by {@code symbolInfo} passing it the arguments in
-     * {@code args}. The values in {@code args} should be native types,e.g., {@code double[]} not
-     * {@code RDoubleVector}.
-     */
-    void invoke(NativeCallInfo nativeCallInfo, Object[] args);
+    abstract class CRFFINode extends Node {
+        /**
+         * Invoke the native method identified by {@code symbolInfo} passing it the arguments in
+         * {@code args}. The values in {@code args} should be native types,e.g., {@code double[]}
+         * not {@code RDoubleVector}.
+         */
+        public abstract void invoke(NativeCallInfo nativeCallInfo, Object[] args);
+    }
+
+    CRFFINode createCRFFINode();
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
index 3029ffce07e33bfd27552919f3916437fb3a93d3..8620608493e7cdee94b262335f988a7db60b54f5 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CallRFFI.java
@@ -22,32 +22,38 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
+
 /**
  * Support for the {.Call} and {.External} calls.
  */
 public interface CallRFFI {
-    /**
-     * Invoke the native function identified by {@code symbolInfo} passing it the arguments in
-     * {@code args}. The values in {@code args} can be any of the types used to represent {@code R}
-     * values in the implementation.
-     */
-    Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args);
+    abstract class CallRFFINode extends Node {
+        /**
+         * Invoke the native function identified by {@code symbolInfo} passing it the arguments in
+         * {@code args}. The values in {@code args} can be any of the types used to represent
+         * {@code R} values in the implementation.
+         */
+        public abstract Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args);
+
+        /**
+         * Variant that does not return a result (primarily for library "init" methods).
+         */
+        public abstract void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args);
 
-    /**
-     * Variant that does not return a result (primarily for library "init" methods).
-     */
-    void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args);
+        /**
+         * This interface is instantiated very early and sets the FFI global variables as part of
+         * that process. However, at that stage {@code tempDir} is not established so this call
+         * exists to set the value later.
+         */
+        public abstract void setTempDir(String tempDir);
 
-    /**
-     * This interface is instantiated very early and sets the FFI global variables as part of that
-     * process. However, at that stage {@code tempDir} is not established so this call exists to set
-     * the value later.
-     */
-    void setTempDir(String tempDir);
+        /**
+         * Sets the {@code R_Interactive} FFI variable. Similar rationale to {#link setTmpDir}.
+         */
+        public abstract void setInteractive(boolean interactive);
+    }
 
-    /**
-     * Sets the {@code R_Interactive} FFI variable. Similar rationale to {#link setTmpDir}.
-     */
-    void setInteractive(boolean interactive);
+    CallRFFINode createCallRFFINode();
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CharSXPWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CharSXPWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7e83255eb8c99e1c347db8bc76d5f03fadcf6c2
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CharSXPWrapper.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+/**
+ * Internally GNU R distinguishes "strings" and "vectors of strings" using the {@code CHARSXP} and
+ * {@code STRSXP} types, respectively. Although this difference is invisible at the R level, it
+ * manifests itself in the R FFI as several functions traffic in the {@code CHARSXP} type. Since
+ * FastR already uses {@code String} to denote a length-1 string vector, it cannot be used to
+ * represent a {@code CHARSXP}, so this class exists to do so.
+ *
+ * N.B. Use limited to RFFI implementations.
+ *
+ */
+public final class CharSXPWrapper {
+    private final String contents;
+
+    private CharSXPWrapper(String contents) {
+        this.contents = contents;
+    }
+
+    public String getContents() {
+        return contents;
+    }
+
+    @Override
+    public String toString() {
+        return "CHARSXP(" + contents + ")";
+    }
+
+    public static Object create(String contents) {
+        return new CharSXPWrapper(contents);
+    }
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
index bceaacfbd4e212370d6dd05252803756e897201e..181da4cc9d31082accd86f6a2728539eb311a475 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java
@@ -13,13 +13,12 @@ package com.oracle.truffle.r.runtime.ffi;
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.Deque;
-import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.RErrorException;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -27,6 +26,7 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
+import com.oracle.truffle.r.runtime.ffi.CallRFFI.CallRFFINode;
 
 /**
  * Support for Dynamically Loaded Libraries.
@@ -46,34 +47,63 @@ import com.oracle.truffle.r.runtime.data.RTruffleObject;
  * <li>support native code of dynamically loaded user packages</li>
  * </ol>
  *
- * In general, unloading a DLL may not be possible, so the set of DLLs have to be considered VM
- * wide, in the sense of multiple {@link RContext}s. TODO what about mutable state in native code?
- * So in the case of multiple {@link RContext}s package shared libraries may be registered multiple
- * times and we must take care not to duplicate them in the meta-data here ({@link #list}).
- *
  * Logic derived from Rdynload.c. For the most part we use the same type/function names as GnuR,
  * e.g. {@link NativeSymbolType}.
+ *
+ * Abstractly every {@link RContext} has its own unique list of loaded libraries, stored in the
+ * {@link ContextStateImpl} class. Concretely, an implementation of the {@link DLLRFFI} may or may
+ * not maintain separate instances.
+ *
+ * The {@code libR} library is a special case, as it is an implementation artifact and not visible
+ * at the R level. However, it is convenient to manage it in a similar way in this code. It is
+ * always stored in slot 0 of the list, and is hidden from R code. It is loaded by the
+ * {@link RFFIFactory} early in the startup, before the initial {@link RContext} is created, by
+ * {@link #loadLibR}. This should only be called once.
  */
 public class DLL {
 
+    public static class ContextStateImpl implements RContext.ContextState {
+        private ArrayList<DLLInfo> list;
+        private RContext context;
+
+        public static ContextStateImpl newContextState() {
+            return new ContextStateImpl();
+        }
+
+        @Override
+        public ContextState initialize(RContext contextArg) {
+            this.context = contextArg;
+            if (context.getKind() == RContext.ContextKind.SHARE_PARENT_RW) {
+                list = context.getParent().stateDLL.list;
+            } else {
+                list = new ArrayList<>();
+                list.add(libRDLLInfo);
+            }
+            return this;
+        }
+
+        @Override
+        public void beforeDestroy(RContext contextArg) {
+            if (context.getKind() != RContext.ContextKind.SHARE_PARENT_RW) {
+                for (int i = 1; i < list.size(); i++) {
+                    DLLInfo dllInfo = list.get(i);
+                    RFFIFactory.getRFFI().getDLLRFFI().dlclose(dllInfo.handle);
+                }
+            }
+            list = null;
+        }
+
+    }
+
     /**
      * The list of loaded DLLs.
      */
-    private static Deque<DLLInfo> list = new ConcurrentLinkedDeque<>();
 
     /**
      * Uniquely identifies the DLL (for use in an {@code externalptr}).
      */
     private static final AtomicInteger ID = new AtomicInteger();
 
-    public static Deque<DLLInfo> getList() {
-        return list;
-    }
-
-    public static void addDLL(DLLInfo dllInfo) {
-        list.add(dllInfo);
-    }
-
     public enum NativeSymbolType {
         C,
         Call,
@@ -144,9 +174,12 @@ public class DLL {
             this.handle = handle;
         }
 
-        private static synchronized DLLInfo create(String name, String path, boolean dynamicLookup, Object handle) {
+        private static DLLInfo create(String name, String path, boolean dynamicLookup, Object handle, boolean addToList) {
             DLLInfo result = new DLLInfo(name, path, dynamicLookup, handle);
-            list.add(result);
+            if (addToList) {
+                ContextStateImpl contextState = getContextState();
+                contextState.list.add(result);
+            }
             return result;
         }
 
@@ -289,6 +322,10 @@ public class DLL {
 
     public static final SymbolHandle SYMBOL_NOT_FOUND = null;
 
+    private static ContextStateImpl getContextState() {
+        return RContext.getInstance().stateDLL;
+    }
+
     public static boolean isDLLInfo(RExternalPtr info) {
         RSymbol tag = (RSymbol) info.getTag();
         return tag.getName().equals(DLLInfo.DLL_INFO_REFERENCE);
@@ -309,53 +346,87 @@ public class DLL {
         }
     }
 
-    /*
-     * There is no sense in throwing an RError if we fail to load/init a (default) package during
-     * initial context initialization, as it is essentially fatal for any of the standard packages
-     * and indicates a bug in the RFFI implementation. So we call Utils.fatalError instead. When the
-     * system is stable, we can undo this, so that errors loading (user) packages added to
-     * R_DEFAULT_PACKAGES do throw RErrors.
+    /**
+     * A temporary stash until such time as the initial context is initialized.
+     */
+    private static DLLInfo libRDLLInfo;
+
+    /**
+     * Loads a the {@code libR} library. This is an implementation specific library N.B., when this
+     * is called for the first time, there is no {@link RContext} available, so we stash the result
+     * until {@link ContextStateImpl#initialize} is called.
      */
+    public static void loadLibR(String path, boolean local, boolean now) throws DLLException {
+        assert libRDLLInfo == null;
+        libRDLLInfo = doLoad(path, local, now, false);
+    }
 
     @TruffleBoundary
-    public static synchronized DLLInfo load(String path, boolean local, boolean now) throws DLLException {
+    public static DLLInfo load(String path, boolean local, boolean now) throws DLLException {
         String absPath = Utils.tildeExpand(path);
-        for (DLLInfo dllInfo : list) {
+        ContextStateImpl contextState = getContextState();
+        for (DLLInfo dllInfo : contextState.list) {
             if (dllInfo.path.equals(absPath)) {
                 // already loaded
                 return dllInfo;
             }
         }
-        File file = new File(absPath);
-        Object handle = RFFIFactory.getRFFI().getDLLRFFI().dlopen(path, local, now);
+        return doLoad(absPath, local, now, true);
+    }
+
+    /*
+     * There is no sense in throwing an RError if we fail to load/init a (default) package during
+     * initial context initialization, as it is essentially fatal for any of the standard packages
+     * and indicates a bug in the RFFI implementation. So we call Utils.fatalError instead. When the
+     * system is stable, we can undo this, so that errors loading (user) packages added to
+     * R_DEFAULT_PACKAGES do throw RErrors.
+     */
+
+    private static DLLInfo doLoad(String absPath, boolean local, boolean now, boolean addToList) throws DLLException {
+        Object handle = RFFIFactory.getRFFI().getDLLRFFI().dlopen(absPath, local, now);
         if (handle == null) {
             String dlError = RFFIFactory.getRFFI().getDLLRFFI().dlerror();
             if (RContext.isInitialContextInitialized()) {
-                throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, dlError);
+                throw new DLLException(RError.Message.DLL_LOAD_ERROR, absPath, dlError);
             } else {
-                throw Utils.rSuicide("error loading default package: " + path + "\n" + dlError);
+                throw Utils.rSuicide("error loading default package: " + absPath + "\n" + dlError);
             }
         }
+        DLLInfo dllInfo = DLLInfo.create(libName(absPath), absPath, true, handle, addToList);
+        return dllInfo;
+    }
+
+    private static String libName(String absPath) {
+        File file = new File(absPath);
         String name = file.getName();
         int dx = name.lastIndexOf('.');
         if (dx > 0) {
             name = name.substring(0, dx);
         }
-        return DLLInfo.create(name, absPath, true, handle);
+        return name;
     }
 
-    private static final String R_INIT_PREFIX = "R_init_";
+    public static final String R_INIT_PREFIX = "R_init_";
 
-    @TruffleBoundary
-    public static DLLInfo loadPackageDLL(String path, boolean local, boolean now) throws DLLException {
-        DLLInfo dllInfo = load(path, local, now);
-        // Search for init method
-        String pkgInit = R_INIT_PREFIX + dllInfo.name;
-        SymbolHandle initFunc = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, pkgInit);
-        if (initFunc != SYMBOL_NOT_FOUND) {
-            synchronized (DLL.class) {
+    public static class LoadPackageDLLNode extends Node {
+        @Child private CallRFFINode callRFFINode;
+
+        public static LoadPackageDLLNode create() {
+            return new LoadPackageDLLNode();
+        }
+
+        @TruffleBoundary
+        public DLLInfo loadPackageDLL(String path, boolean local, boolean now) throws DLLException {
+            DLLInfo dllInfo = load(path, local, now);
+            // Search for init method
+            String pkgInit = R_INIT_PREFIX + dllInfo.name;
+            SymbolHandle initFunc = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, pkgInit);
+            if (initFunc != SYMBOL_NOT_FOUND) {
                 try {
-                    RFFIFactory.getRFFI().getCallRFFI().invokeVoidCall(new NativeCallInfo(pkgInit, initFunc, dllInfo), new Object[]{dllInfo});
+                    if (callRFFINode == null) {
+                        callRFFINode = insert(RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode());
+                    }
+                    callRFFINode.invokeVoidCall(new NativeCallInfo(pkgInit, initFunc, dllInfo), new Object[]{dllInfo});
                 } catch (ReturnException ex) {
                     // An error call can, due to condition handling, throw this which we must
                     // propogate
@@ -368,28 +439,33 @@ public class DLL {
                     }
                 }
             }
+            return dllInfo;
         }
-        return dllInfo;
     }
 
     @TruffleBoundary
-    public static synchronized void unload(String path) throws DLLException {
+    public static void unload(String path) throws DLLException {
         String absPath = Utils.tildeExpand(path);
-        for (DLLInfo info : list) {
+        ContextStateImpl contextState = getContextState();
+        for (DLLInfo info : contextState.list) {
             if (info.path.equals(absPath)) {
                 int rc = RFFIFactory.getRFFI().getDLLRFFI().dlclose(info.handle);
                 if (rc != 0) {
                     throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, "");
                 }
+                contextState.list.remove(info);
                 return;
             }
         }
         throw new DLLException(RError.Message.DLL_NOT_LOADED, path);
     }
 
-    public static synchronized ArrayList<DLLInfo> getLoadedDLLs() {
+    public static ArrayList<DLLInfo> getLoadedDLLs() {
         ArrayList<DLLInfo> result = new ArrayList<>();
-        for (DLLInfo dllInfo : list) {
+        ContextStateImpl contextState = getContextState();
+        // skip first entry (libR)
+        for (int i = 1; i < contextState.list.size(); i++) {
+            DLLInfo dllInfo = contextState.list.get(i);
             result.add(dllInfo);
         }
         return result;
@@ -465,9 +541,10 @@ public class DLL {
      *            {@code null})
      */
     @TruffleBoundary
-    public static synchronized SymbolHandle findSymbol(String name, String libName, RegisteredNativeSymbol rns) {
+    public static SymbolHandle findSymbol(String name, String libName, RegisteredNativeSymbol rns) {
         boolean all = libName == null || libName.length() == 0;
-        for (DLLInfo dllInfo : list) {
+        ContextStateImpl contextState = getContextState();
+        for (DLLInfo dllInfo : contextState.list) {
             if (dllInfo.forceSymbols) {
                 continue;
             }
@@ -487,8 +564,9 @@ public class DLL {
         return SYMBOL_NOT_FOUND;
     }
 
-    public static synchronized DLLInfo findLibrary(String name) {
-        for (DLLInfo dllInfo : list) {
+    public static DLLInfo findLibrary(String name) {
+        ContextStateImpl contextState = getContextState();
+        for (DLLInfo dllInfo : contextState.list) {
             if (dllInfo.name.equals(name)) {
                 return dllInfo;
             }
@@ -529,7 +607,7 @@ public class DLL {
     public static DLLInfo getEmbeddingDLLInfo() {
         DLLInfo result = findLibrary(EMBEDDING);
         if (result == null) {
-            result = DLLInfo.create(EMBEDDING, EMBEDDING, false, null);
+            result = DLLInfo.create(EMBEDDING, EMBEDDING, false, null, true);
         }
         return result;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIRootNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIRootNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..00c8ed1b5f521e25244303b467ad901847642534
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIRootNode.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+import com.oracle.truffle.api.RootCallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.FrameDescriptor;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RNull;
+
+public final class FFIRootNode extends RootNode {
+    @Child private CallRFFI.CallRFFINode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode();
+
+    public FFIRootNode() {
+        super(RContext.getRRuntimeASTAccess().getTruffleRLanguage(), null, new FrameDescriptor());
+
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        Object[] args = frame.getArguments();
+        NativeCallInfo nativeCallInfo = (NativeCallInfo) args[0];
+        boolean isVoidCall = (boolean) args[1];
+        Object[] callArgs = (Object[]) args[2];
+        if (isVoidCall) {
+            callRFFINode.invokeVoidCall(nativeCallInfo, callArgs);
+            return RNull.instance;
+        } else {
+            return callRFFINode.invokeCall(nativeCallInfo, callArgs);
+        }
+    }
+
+    public static RootCallTarget createCallTarget() {
+        return Truffle.getRuntime().createCallTarget(new FFIRootNode());
+    }
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/GridRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/GridRFFI.java
index 561ba671024c66baf1db51eacd3776bc0b218778..9d410b1054b72fa146627a30012e09c103dbdcc8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/GridRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/GridRFFI.java
@@ -22,10 +22,15 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public interface GridRFFI {
-    Object initGrid(REnvironment gridEvalEnv);
+    abstract class GridRFFINode extends Node {
+        public abstract Object initGrid(REnvironment gridEvalEnv);
 
-    Object killGrid();
+        public abstract Object killGrid();
+    }
+
+    GridRFFINode createGridRFFINode();
 }
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 9d537ec5006221e9796736eaf19bc85e645631c0..a8f3622fa426a6c5a8d5070705abf8a160e4ed08 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,67 +22,73 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
+
 /**
  * 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.
  */
 public interface LapackRFFI {
-    /**
-     * Return version info, mjor, minor, patch, in {@code version}.
-     */
-    void ilaver(int[] version);
+    abstract class LapackRFFINode extends Node {
+        /**
+         * Return version info, mjor, minor, patch, in {@code version}.
+         */
+        public abstract void ilaver(int[] version);
+
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/d9/d28/dgeev_8f.html">spec</a>.
+         */
+        public abstract int dgeev(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);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/d9/d28/dgeev_8f.html">spec</a>.
-     */
-    int dgeev(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);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/db/de5/dgeqp3_8f.html">spec</a>.
+         */
+        public abstract int dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/db/de5/dgeqp3_8f.html">spec</a>.
-     */
-    int dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work, int lwork);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/da/d82/dormqr_8f.html">spec</a>.
+         */
+        public abstract int dormqr(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/da/d82/dormqr_8f.html">spec</a>.
-     */
-    int dormqr(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work, int lwork);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/d6/d6f/dtrtrs_8f.html">spec</a>.
+         */
+        public abstract int dtrtrs(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/d6/d6f/dtrtrs_8f.html">spec</a>.
-     */
-    int dtrtrs(char uplo, char trans, char diag, int n, int nrhs, double[] a, int lda, double[] b, int ldb);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/d3/d6a/dgetrf_8f.html">spec</a>.
+         */
+        public abstract int dgetrf(int m, int n, double[] a, int lda, int[] ipiv);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/d3/d6a/dgetrf_8f.html">spec</a>.
-     */
-    int dgetrf(int m, int n, double[] a, int lda, int[] ipiv);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/d0/d8a/dpotrf_8f.html">spec</a>.
+         */
+        public abstract int dpotrf(char uplo, int n, double[] a, int lda);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/d0/d8a/dpotrf_8f.html">spec</a>.
-     */
-    int dpotrf(char uplo, int n, double[] a, int lda);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/dd/dad/dpstrf_8f.html">spec</a>.
+         */
+        public abstract int dpstrf(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/dd/dad/dpstrf_8f.html">spec</a>.
-     */
-    int dpstrf(char uplo, int n, double[] a, int lda, int[] piv, int[] rank, double tol, double[] work);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/d8/d72/dgesv_8f.html">spec</a>.
+         */
+        public abstract int dgesv(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/d8/d72/dgesv_8f.html">spec</a>.
-     */
-    int dgesv(int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/dc/d09/dlange_8f.html">spec</a>.
+         */
+        public abstract double dlange(char norm, int m, int n, double[] a, int lda, double[] work);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/dc/d09/dlange_8f.html">spec</a>.
-     */
-    double dlange(char norm, int m, int n, double[] a, int lda, double[] work);
+        /**
+         * See <a href="http://www.netlib.org/lapack/explore-html/db/de4/dgecon_8f.html">spec</a>.
+         */
+        public abstract int dgecon(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork);
 
-    /**
-     * See <a href="http://www.netlib.org/lapack/explore-html/db/de4/dgecon_8f.html">spec</a>.
-     */
-    int dgecon(char norm, int n, double[] a, int lda, double anorm, double[] rcond, double[] work, int[] iwork);
+        public abstract int dsyevr(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);
+    }
 
-    int dsyevr(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);
+    LapackRFFINode createLapackRFFINode();
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallInfo.java
index b2559c719ee30f9e3880a1016448c05b851d2f01..c904948ab6afcacfcb6f7fe3a54dec1fadccc220 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallInfo.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeCallInfo.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
@@ -42,4 +43,10 @@ public final class NativeCallInfo {
         this.address = address;
         this.dllInfo = dllInfo;
     }
+
+    @Override
+    public String toString() {
+        CompilerAsserts.neverPartOfCompilation();
+        return String.format("dll: %s, name: %s", dllInfo.name, name);
+    }
 }
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 1825446c61a5d71aa069c44c0460febb2b902922..cff6aadebf60cdce9f6b0f3aa44fd5789218a020 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
+
 /**
  * An interface to the <a href="http://www.pcre.org/original/doc/html/index.html">PCRE</a> library
  * for Perl regular expressions.
@@ -47,16 +49,21 @@ public interface PCRERFFI {
         }
     }
 
-    long maketables();
+    abstract class PCRERFFINode extends Node {
+
+        public abstract long maketables();
 
-    Result compile(String pattern, int options, long tables);
+        public abstract Result compile(String pattern, int options, long tables);
 
-    int getCaptureCount(long code, long extra);
+        public abstract int getCaptureCount(long code, long extra);
 
-    String[] getCaptureNames(long code, long extra, int captureCount);
+        public abstract String[] getCaptureNames(long code, long extra, int captureCount);
 
-    Result study(long code, int options);
+        public abstract Result study(long code, int options);
+
+        public abstract int exec(long code, long extra, String subject, int offset, int options, int[] ovector);
+    }
 
-    int exec(long code, long extra, String subject, int offset, int options, int[] ovector);
+    PCRERFFINode createPCRERFFINode();
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ParseResult.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ParseResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4c71e01bd9db7b54b821bdeec2afda8ea9589b6
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ParseResult.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+/**
+ * Used in implementation of {@link UpCallsRFFI#R_ParseVector(Object, int, Object)}.
+ */
+public class ParseResult {
+    public enum ParseStatus {
+        PARSE_NULL,
+        PARSE_OK,
+        PARSE_INCOMPLETE,
+        PARSE_ERROR,
+        PARSE_EOF
+    }
+
+    @SuppressWarnings("unused") private final int parseStatus;
+    @SuppressWarnings("unused") private final Object expr;
+
+    ParseResult(int parseStatus, Object expr) {
+        this.parseStatus = parseStatus;
+        this.expr = expr;
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RApplRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RApplRFFI.java
index 4f20c85d9b914cd51b4ae9ef42aa7da45a300317..189f88165c856c4296e52f25bdb2be52f43ec268 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RApplRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RApplRFFI.java
@@ -22,17 +22,23 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
+
 /**
  * Collection of statically typed methods (from Linpack and elsewhere) that are built in to a GnuR
  * implementation and factored out into a separate library in FastR. This corresponds to the
  * {@code libappl} library in GnuR.
  */
 public interface RApplRFFI {
-    // Linpack
-    void dqrdc2(double[] x, int ldx, int n, int p, double tol, int[] rank, double[] qraux, int[] pivot, double[] work);
+    abstract class RApplRFFINode extends Node {
+        // Linpack
+        public abstract void dqrdc2(double[] x, int ldx, int n, int p, double tol, int[] rank, double[] qraux, int[] pivot, double[] work);
+
+        public abstract void dqrcf(double[] x, int n, int k, double[] qraux, double[] y, int ny, double[] b, int[] info);
 
-    void dqrcf(double[] x, int n, int k, double[] qraux, double[] y, int ny, double[] b, int[] info);
+        public abstract void dqrls(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);
+    }
 
-    void dqrls(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);
+    RApplRFFINode createRApplRFFINode();
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
index 99378fa1afaf28b7dc52b531356a846330d4edd2..ccc6224ba183630e07ad2a4ca7dce1ccb2c14766 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFI.java
@@ -42,6 +42,9 @@ package com.oracle.truffle.r.runtime.ffi;
  * <li>{@link DLLRFFI}: interface to dll functions, e.g., {@code dlopen}</li>
  * <li>{@link REmbedRFFI}: interface to embedded support</li>
  * <li>{@link MiscRFFI}: interface to miscellaneous native functions</li>
+ * <li>{@link UpCallsRFFI}: interface that defines the set of upcalls from native code (resulting
+ * from {@link CallRFFI}). There is no public access to this interface as it should never be called
+ * from FastR Java code and is always implemented by a specific FFI factory.
  * </ul>
  *
  * These interfaces may be implemented by one or more providers, specified either when the FastR
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 a796d4fb612f4ae24a80ab1d21b5929199e38f48..67adab0639211e28786f15af9be6578e12abcdb6 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, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,13 +22,20 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
+
 /**
- * Interface to native (C) methods provided by the {@code stats} package.
+ * 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 fft_factor} and {@code fft_work}. functions from the GNU R C code.
  */
 public interface StatsRFFI {
-    // Checkstyle: stop method name
-    void fft_factor(int n, int[] pmaxf, int[] pmaxp);
+    abstract class FFTNode extends Node {
+        public abstract void executeFactor(int n, int[] pmaxf, int[] pmaxp);
+
+        public abstract int executeWork(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork);
+    }
 
-    int fft_work(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork);
+    FFTNode createFFTNode();
 
 }
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 04bc7e21a310117776602427c0dee389e3154b6b..290daad5f02a030ce1c177c3b461f7332fb3fae4 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.conn.RConnection;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -31,14 +32,18 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  * Interface to native (C) methods provided by the {@code tools} package.
  */
 public interface ToolsRFFI {
-    /**
-     * 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, ...)},
-     * which has a custom specialization in the implementation of the {@code .External2} builtin.
-     * That does some work in Java, and then calls this method to invoke the actual C 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 parseRd(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
-                    RLogicalVector warndups);
+    abstract class ToolsRFFINode extends Node {
+        /**
+         * 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, ...)}
+         * , which has a custom specialization in the implementation of the {@code .External2}
+         * builtin. That does some work in Java, and then calls this method to invoke the actual C
+         * 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.
+         */
+        public abstract Object parseRd(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
+                        RLogicalVector warndups);
+    }
+
+    ToolsRFFINode createToolsRFFINode();
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UpCallsRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UpCallsRFFI.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccfb5fa901804eb5d13cc1f0858d736fe1c0cc4d
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UpCallsRFFI.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RExternalPtr;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RLogicalVector;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+
+/**
+ * This class defines methods that match the functionality of the macro/function definitions in the
+ * R header files, e.g. {@code Rinternals.h} that are used by C/C++ code to call into the R
+ * implementation. For ease of identification, we use method names that match the names in the R
+ * header files. These methods should never be called from normal FastR code.
+ *
+ * The set is incomplete; these are the functions that have been found to be used to at this time of
+ * writing. From the GNU R perspective all {@code Object} parameters are {@code SEXP} instances.
+ * Some of the functions are typed with a specific return type but, again, this is a {@code SEXP} in
+ * GNU R terms. The native side does not require a specific Java type.
+ *
+ */
+public interface UpCallsRFFI {
+
+    // Checkstyle: stop method name check
+
+    RIntVector Rf_ScalarInteger(int value);
+
+    RLogicalVector Rf_ScalarLogical(int value);
+
+    RDoubleVector Rf_ScalarDouble(double value);
+
+    RStringVector Rf_ScalarString(Object value);
+
+    int Rf_asInteger(Object x);
+
+    double Rf_asReal(Object x);
+
+    int Rf_asLogical(Object x);
+
+    Object Rf_asChar(Object x);
+
+    Object Rf_mkCharLenCE(byte[] bytes, int encoding);
+
+    Object Rf_cons(Object car, Object cdr);
+
+    void Rf_defineVar(Object symbolArg, Object value, Object envArg);
+
+    Object R_do_MAKE_CLASS(String clazz);
+
+    /**
+     * WARNING: argument order reversed from Rf_findVarInFrame!
+     */
+    Object Rf_findVar(Object symbolArg, Object envArg);
+
+    Object Rf_findVarInFrame(Object envArg, Object symbolArg);
+
+    Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet);
+
+    Object Rf_getAttrib(Object obj, Object name);
+
+    void Rf_setAttrib(Object obj, Object name, Object val);
+
+    int Rf_inherits(Object x, String clazz);
+
+    Object Rf_install(String name);
+
+    Object Rf_lengthgets(Object x, int newSize);
+
+    int Rf_isString(Object x);
+
+    int Rf_isNull(Object x);
+
+    Object Rf_PairToVectorList(Object x);
+
+    void Rf_error(String msg);
+
+    void Rf_warning(String msg);
+
+    void Rf_warningcall(Object call, String msg);
+
+    Object Rf_allocateVector(int mode, int n);
+
+    Object Rf_allocateArray(int mode, Object dimsObj);
+
+    Object Rf_allocateMatrix(int mode, int nrow, int ncol);
+
+    int Rf_nrows(Object x);
+
+    int Rf_ncols(Object x);
+
+    int LENGTH(Object x);
+
+    void SET_STRING_ELT(Object x, int i, Object v);
+
+    void SET_VECTOR_ELT(Object x, int i, Object v);
+
+    Object RAW(Object x);
+
+    Object LOGICAL(Object x);
+
+    Object INTEGER(Object x);
+
+    Object REAL(Object x);
+
+    Object STRING_ELT(Object x, int i);
+
+    Object VECTOR_ELT(Object x, int i);
+
+    int NAMED(Object x);
+
+    Object SET_TYPEOF_FASTR(Object x, int v);
+
+    int TYPEOF(Object x);
+
+    int OBJECT(Object x);
+
+    Object Rf_duplicate(Object x, int deep);
+
+    int Rf_anyDuplicated(Object x, int fromLast);
+
+    Object PRINTNAME(Object x);
+
+    Object TAG(Object e);
+
+    Object CAR(Object e);
+
+    Object CDR(Object e);
+
+    Object CADR(Object e);
+
+    Object CADDR(Object e);
+
+    Object CDDR(Object e);
+
+    Object SET_TAG(Object x, Object y);
+
+    Object SETCAR(Object x, Object y);
+
+    Object SETCDR(Object x, Object y);
+
+    Object SETCADR(Object x, Object y);
+
+    Object SYMVALUE(Object x);
+
+    void SET_SYMVALUE(Object x, Object v);
+
+    int R_BindingIsLocked(Object sym, Object env);
+
+    Object R_FindNamespace(Object name);
+
+    Object Rf_eval(Object expr, Object env);
+
+    Object Rf_findfun(Object symbolObj, Object envObj);
+
+    Object Rf_GetOption1(Object tag);
+
+    void Rf_gsetVar(Object symbol, Object value, Object rho);
+
+    void DUPLICATE_ATTRIB(Object to, Object from);
+
+    int R_computeIdentical(Object x, Object y, int flags);
+
+    void Rf_copyListMatrix(Object s, Object t, int byrow);
+
+    void Rf_copyMatrix(Object s, Object t, int byrow);
+
+    Object R_tryEval(Object expr, Object env, boolean silent);
+
+    Object R_ToplevelExec();
+
+    int RDEBUG(Object x);
+
+    void SET_RDEBUG(Object x, int v);
+
+    int RSTEP(Object x);
+
+    void SET_RSTEP(Object x, int v);
+
+    Object ENCLOS(Object x);
+
+    Object PRVALUE(Object x);
+
+    Object R_ParseVector(Object text, int n, Object srcFile);
+
+    Object R_lsInternal3(Object envArg, int allArg, int sortedArg);
+
+    String R_HomeDir();
+
+    int isInteractive();
+
+    int isS4Object(Object x);
+
+    void Rprintf(String message);
+
+    void GetRNGstate();
+
+    void PutRNGstate();
+
+    double unif_rand();
+
+    Object Rf_classgets(Object x, Object y);
+
+    RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot);
+
+    long R_ExternalPtrAddr(Object x);
+
+    Object R_ExternalPtrTag(Object x);
+
+    Object R_ExternalPtrProt(Object x);
+
+    void R_SetExternalPtrAddr(Object x, long addr);
+
+    void R_SetExternalPtrTag(Object x, Object tag);
+
+    void R_SetExternalPtrProt(Object x, Object prot);
+
+    void R_CleanUp(int sa, int status, int runlast);
+
+    REnvironment R_NewHashedEnv(REnvironment parent, String name, boolean hashed, int initialSize);
+
+    /*
+     * The following functions are global variables in the standard R FFI. However, owing to the
+     * support for virtual R sessions (see .fastr.context) in FastR they are remapped as functions.
+     */
+    Object R_GlobalContext();
+
+    Object R_GlobalEnv();
+
+    Object R_BaseEnv();
+
+    Object R_BaseNamespace();
+
+    Object R_NamespaceRegistry();
+
+    /*
+     * The following functions are FastR extensions to support RStudio
+     */
+
+    Object R_getGlobalFunctionContext();
+
+    Object R_getParentFunctionContext(Object c);
+
+    Object R_getContextEnv(Object c);
+
+    Object R_getContextFun(Object c);
+
+    Object R_getContextCall(Object c);
+
+    Object R_getContextSrcRef(Object c);
+
+    int R_insideBrowser();
+
+    int R_isGlobal(Object c);
+
+    int R_isEqual(Object x, Object y);
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UpCallsRFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UpCallsRFFIFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad90095e5d43c62b89736d67dc05c0a60d035c1a
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UpCallsRFFIFactory.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi;
+
+public abstract class UpCallsRFFIFactory {
+    static {
+        final String prop = System.getProperty("fastr.upcalls.factory.class", "com.oracle.truffle.r.runtime.ffi.JavaUpCallsRFFIFactory");
+        try {
+            theInstance = (UpCallsRFFIFactory) Class.forName(prop).newInstance();
+        } catch (Exception ex) {
+            // CheckStyle: stop system..print check
+            System.err.println("Failed to instantiate class: " + prop);
+        }
+    }
+
+    private static UpCallsRFFIFactory theInstance;
+
+    public static UpCallsRFFIFactory getInstance() {
+        return theInstance;
+    }
+
+    public abstract UpCallsRFFI getUpcallsRFFI();
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java
index dc692727fcfe6b46100e854a859d63ec0abaa700..64059decbdafae4071c9165e91a345da6c2f313d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UserRngRFFI.java
@@ -22,17 +22,23 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.nodes.Node;
+
 /**
  * Explicit statically typed interface to user-supplied random number generators.
  */
 public interface UserRngRFFI {
+    abstract class UserRngRFFINode extends Node {
+
+        public abstract void init(int seed);
 
-    void init(int seed);
+        public abstract double rand();
 
-    double rand();
+        public abstract int nSeed();
 
-    int nSeed();
+        public abstract void seeds(int[] n);
+    }
 
-    void seeds(int[] n);
+    UserRngRFFINode createUserRngRFFINode();
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
index c3538fa9a79e69624a844b784275b7a3b2dd0d40..fa6e33017ba7329a1d9810df5051c8da746174dc 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java
@@ -110,7 +110,8 @@ public abstract class BinaryArithmetic extends Operation {
     public abstract String op(String left, String right);
 
     public static double fmod(double a, double b) {
-        // LICENSE: transcribed code from GNU R, which is licensed under GPL
+        // TODO: this is duplicated in RMath, once RMath is moved to runtime, this should be
+        // replaced
         double q = a / b;
         if (b != 0) {
             double tmp = a - Math.floor(q) * b;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java
index 84187071f92296f69c96bec987616bcefd1d0270..b8490dfaae54f03a4c1fae79f647be644b5ce418 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/user/UserRNG.java
@@ -23,7 +23,15 @@
 package com.oracle.truffle.r.runtime.rng.user;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.RootCallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.FrameDescriptor;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
@@ -66,28 +74,67 @@ public final class UserRNG implements RandomNumberGenerator {
 
     }
 
-    private UserRngRFFI userRngRFFI;
     private int nSeeds = 0;
 
+    private abstract static class UserRNGRootNodeAdapter extends RootNode {
+        @Child protected UserRngRFFI.UserRngRFFINode userRngRFFINode = RFFIFactory.getRFFI().getUserRngRFFI().createUserRngRFFINode();
+
+        protected UserRNGRootNodeAdapter() {
+            super(RContext.getRRuntimeASTAccess().getTruffleRLanguage(), null, new FrameDescriptor());
+        }
+    }
+
+    private static final class GenericUserRNGRootNode extends UserRNGRootNodeAdapter {
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            Function function = (Function) args[0];
+            switch (function) {
+                case Init:
+                    userRngRFFINode.init((int) args[1]);
+                    return RNull.instance;
+                case NSeed:
+                    return userRngRFFINode.nSeed();
+                case Seedloc:
+                    userRngRFFINode.seeds((int[]) args[1]);
+                    return RNull.instance;
+                default:
+                    throw RInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    private static final class RandUserRNGRootNode extends UserRNGRootNodeAdapter {
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return userRngRFFINode.rand();
+        }
+
+    }
+
+    private RootCallTarget callGeneric;
+    private RootCallTarget callRand;
+
     @Override
     @TruffleBoundary
     public void init(int seed) {
         DLLInfo dllInfo = DLL.findLibraryContainingSymbol(Function.Rand.symbol);
+        callGeneric = Truffle.getRuntime().createCallTarget(new GenericUserRNGRootNode());
         if (dllInfo == null) {
             throw RError.error(RError.NO_CALLER, RError.Message.RNG_SYMBOL, Function.Rand.symbol);
         }
         for (Function f : Function.values()) {
             f.setSymbolHandle(dllInfo);
         }
-        userRngRFFI = RFFIFactory.getRFFI().getUserRngRFFI();
         if (Function.Init.isDefined()) {
-            userRngRFFI.init(seed);
+            callGeneric.call(Function.Init, seed);
         }
         if (Function.Seedloc.isDefined() && !Function.NSeed.isDefined()) {
             RError.warning(RError.NO_CALLER, RError.Message.RNG_READ_SEEDS);
         }
         if (Function.NSeed.isDefined()) {
-            int ns = userRngRFFI.nSeed();
+            int ns = (int) callGeneric.call(Function.NSeed);
             if (ns < 0 || ns > 625) {
                 RError.warning(RError.NO_CALLER, RError.Message.GENERIC, "seed length must be in 0...625; ignored");
             } else {
@@ -98,6 +145,7 @@ public final class UserRNG implements RandomNumberGenerator {
                  */
             }
         }
+        callRand = Truffle.getRuntime().createCallTarget(new RandUserRNGRootNode());
     }
 
     private static DLL.SymbolHandle findSymbol(String symbol, DLLInfo dllInfo, boolean optional) {
@@ -125,7 +173,7 @@ public final class UserRNG implements RandomNumberGenerator {
             return null;
         }
         int[] seeds = new int[nSeeds];
-        userRngRFFI.seeds(seeds);
+        callGeneric.call(Function.Seedloc, seeds);
         int[] result = new int[nSeeds + 1];
         System.arraycopy(seeds, 0, result, 1, seeds.length);
         return result;
@@ -133,7 +181,7 @@ public final class UserRNG implements RandomNumberGenerator {
 
     @Override
     public double genrandDouble() {
-        return userRngRFFI.rand();
+        return (double) callRand.call();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/NAMESPACE b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/NAMESPACE
index e8d3772855c8cf98879a21dea3dcfd271e657c79..d4740fb354292dca72ba1633e4f2446b6d0858f4 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/NAMESPACE
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/NAMESPACE
@@ -1,5 +1,5 @@
 ## package has a dynamic library
-useDynLib(testrffi)
+useDynLib(testrffi, .registration = TRUE, .fixes = "C_")
 
 ## and exported functions
 exportPattern("rffi\\..*")
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
index 6f53923b5377add006be17e501fd321463e2ffff..54c5c79209d12d65cbee830a6d24a19af28e9fc4 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R
@@ -1,3 +1,6 @@
+.onUnload <- function(libpath)
+	library.dynam.unload("testrffi", libpath)
+
 rffi.dotCModifiedArguments <- function(data) {
 	.C("dotCModifiedArguments", length(data), as.integer(data), as.double(data), as.logical(data))
 }
@@ -83,10 +86,6 @@ rffi.mkStringFromBytes <- function() {
 	.Call("mkStringFromBytes", PACKAGE = "testrffi")
 }
 
-rffi.null <- function() {
-	.Call("null", PACKAGE = "testrffi")
-}
-
 rffi.iterate_iarray <- function(x) {
 	.Call("iterate_iarray", x, PACKAGE = "testrffi")
 }
@@ -110,3 +109,16 @@ rffi.findvar <- function(x, env) {
 	.Call("findvar", x, env, PACKAGE = "testrffi")
 }
 
+rffi.null <- function() {
+	.Call("null", PACKAGE = "testrffi")
+}
+
+rffi.null.E <- function() {
+	.Call("null", PACKAGE = "foo")
+}
+
+rffi.null.C <- function() {
+	.Call(C_null)
+}
+
+
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
index f46e8f1d2cf1125e443674261b0ef62f4c0caae6..5af8e6bb9f7b8298be0b5a6ee5a99fafd51ffe25 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/init.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,11 +22,47 @@
  */
 #include <R.h>
 #include <Rinternals.h>
-
 #include <R_ext/Rdynload.h>
+#include "testrffi.h"
+
+static const R_CMethodDef CEntries[]  = {
+    {"dotCModifiedArguments", (DL_FUNC) &dotCModifiedArguments, 4},
+    {NULL, NULL, 0}
+};
+
+#define CALLDEF(name, n)  {#name, (DL_FUNC) &name, n}
+
+static const R_CallMethodDef CallEntries[] = {
+	    CALLDEF(addInt, 2),
+	    CALLDEF(addDouble, 2),
+	    CALLDEF(populateIntVector, 1),
+	    CALLDEF(populateLogicalVector, 1),
+	    CALLDEF(createExternalPtr, 3),
+	    CALLDEF(getExternalPtrAddr, 1),
+	    CALLDEF(invoke_TYPEOF, 1),
+	    CALLDEF(invoke_error, 1),
+	    CALLDEF(dot_external_access_args, 1),
+	    CALLDEF(invoke_isString, 1),
+	    CALLDEF(invoke12, 12),
+	    CALLDEF(interactive, 0),
+	    CALLDEF(tryEval, 2),
+	    CALLDEF(rHomeDir, 0),
+	    CALLDEF(nestedCall1, 2),
+	    CALLDEF(nestedCall2, 1),
+	    CALLDEF(r_home, 0),
+	    CALLDEF(mkStringFromChar, 0),
+	    CALLDEF(mkStringFromBytes, 0),
+	    CALLDEF(null, 0),
+	    CALLDEF(iterate_iarray, 1),
+	    CALLDEF(iterate_iptr, 1),
+	    CALLDEF(preserve_object, 0),
+	    CALLDEF(release_object, 1),
+	    CALLDEF(findvar, 2),
+	    {NULL, NULL, 0}
+};
 
 void
 R_init_testrffi(DllInfo *dll)
 {
-    R_registerRoutines(dll, NULL, NULL, NULL, NULL);
+    R_registerRoutines(dll, CEntries, CallEntries, NULL, NULL);
 }
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
index 61f4862f88ee9e9ae9ea2f93e8c919517571f6c5..771587f95b8d1c384aa93b646a37563a6f0d1d04 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c
@@ -28,6 +28,7 @@
 #include <Rinterface.h>
 #include <Rinternals.h>
 #include <Rinterface.h>
+#include "testrffi.h"
 
 void dotCModifiedArguments(int* len, int* idata, double* rdata, int* ldata) {
     for (int i = 0; i < len[0]; i++) {
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
new file mode 100644
index 0000000000000000000000000000000000000000..44de64f3dacf7f6b4dcda78ca61fe0ab4b58eff2
--- /dev/null
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+extern void dotCModifiedArguments(int* len, int* idata, double* rdata, int* ldata);
+
+extern SEXP addInt(SEXP a, SEXP b);
+
+extern SEXP addDouble(SEXP a, SEXP b);
+
+extern SEXP populateIntVector(SEXP n);
+
+extern SEXP populateLogicalVector(SEXP n);
+
+extern SEXP createExternalPtr(SEXP addr, SEXP tag, SEXP prot);
+
+extern SEXP getExternalPtrAddr(SEXP eptr);
+
+extern SEXP invoke_TYPEOF(SEXP x);
+
+extern SEXP invoke_error(SEXP msg);
+
+extern SEXP dot_external_access_args(SEXP args);
+
+extern SEXP invoke_isString(SEXP s);
+
+extern SEXP invoke12(SEXP a1, SEXP a2, SEXP a3, SEXP a4, SEXP a5, SEXP a6, SEXP a7, SEXP a8, SEXP a9, SEXP a10, SEXP a11, SEXP a12);
+
+extern SEXP interactive(void);
+
+extern SEXP tryEval(SEXP expr, SEXP env);
+
+extern SEXP rHomeDir();
+
+extern SEXP nestedCall1(SEXP upcall, SEXP env);
+
+extern SEXP nestedCall2(SEXP v);
+
+extern SEXP r_home(void);
+
+extern SEXP mkStringFromChar(void);
+
+extern SEXP mkStringFromBytes(void);
+
+extern SEXP null(void);
+
+extern SEXP iterate_iarray(SEXP x);
+
+extern SEXP iterate_iptr(SEXP x);
+
+extern SEXP preserve_object(void);
+
+extern SEXP release_object(SEXP x);
+
+extern SEXP findvar(SEXP x, SEXP env);
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 411da557d81edc47a44d8cbd349fda7e8e3d329f..8fef252e8753cf9ccc3ec41ebc0250fcd584ecfe 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -120,6 +120,10 @@ Slot "j":
 [1] 42
 
 
+##com.oracle.truffle.r.test.S4.TestS4.testAllocation#
+#{ setClass("foo", representation(j="numeric")); typeof(new("foo", j=42)) }
+[1] "S4"
+
 ##com.oracle.truffle.r.test.S4.TestS4.testClassCreation#
 #{ setClass("foo"); setClass("bar", representation(j = "numeric"), contains = "foo"); is.null(getClass("foo")@prototype) }
 [1] FALSE
@@ -2717,6 +2721,34 @@ In anyDuplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") :
 #anyNA(list(list(c(NA)),c(1)), recursive=c(FALSE,TRUE))
 [1] FALSE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(c(1, 2, 3))
+[1] FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(c(1, NA, 3))
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(c(1, NA, 3), recursive = TRUE)
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c(1, 2, 3), b = 'a'))
+[1] FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c(1, 2, 3), b = 'a'), recursive = TRUE)
+[1] FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c(1, NA, 3), b = 'a'))
+[1] FALSE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3#
+#anyNA(list(a = c(1, NA, 3), b = 'a'), recursive = TRUE)
+[1] TRUE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_aperm.testAperm#
 #{ a = array(1:24,c(2,3,4)); b = aperm(a); c(dim(b)[1],dim(b)[2],dim(b)[3]) }
 [1] 4 3 2
@@ -5370,7 +5402,7 @@ character(0)
 #{ as.character(list(c(2L, 3L))) }
 [1] "2:3"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testAsCharacter#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testAsCharacter#
 #{ as.character(list(c(2L, 3L, 5L))) }
 [1] "c(2, 3, 5)"
 
@@ -5562,7 +5594,7 @@ character(0)
 #argv <- list(c(-4, 4, 3.99, -1, -3.01));as.character(argv[[1]]);
 [1] "-4"    "4"     "3.99"  "-1"    "-3.01"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testascharacter36#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testascharacter36#
 #argv <- list(list(exit.code = 0L, send = NULL));as.character(argv[[1]]);
 [1] "0"    "NULL"
 
@@ -16373,7 +16405,7 @@ invalid 'cutoff' value for 'deparse', using default
 #{ det(matrix(c(1,-3,4,-5),nrow=2)) }
 [1] 7
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_det.testDet#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_det.testDet#
 #{ det(matrix(c(1,0,4,NA),nrow=2)) }
 [1] NA
 
@@ -17916,6 +17948,10 @@ NULL
      [,1]
 [1,]   NA
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_dimassign.testdimassign12#
+#b <- c(a=1+2i,b=3+4i);dim(b) <- c(2,1);attributes(x)
+Error: object 'x' not found
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_dimassign.testdimassign2#
 #argv <- list(structure(logical(0), .Dim = c(0L, 0L)), value = c(0L, 0L));`dim<-`(argv[[1]],argv[[2]]);
 <0 x 0 matrix>
@@ -22493,7 +22529,7 @@ attr(,"Rd_tag")
 #argv <- list(structure(c(NA, 2, NA, 1, NA, 0), .Dim = 2:3), structure(c(NA, 2, NA, 1, NA, 0), .Dim = 2:3), TRUE, TRUE, TRUE, TRUE, FALSE); .Internal(identical(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))
 [1] TRUE
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testidentical20#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testidentical20#
 #argv <- list(NaN, NaN, TRUE, TRUE, TRUE, TRUE, FALSE); .Internal(identical(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))
 [1] TRUE
 
@@ -22561,7 +22597,7 @@ attr(,"Rd_tag")
 #argv <- structure(list(x = structure(list(X1.4 = 1:4), .Names = 'X1.4',     row.names = c(NA, -4L), class = 'data.frame'), y = structure(list(X1.4 = 1:4),     .Names = 'X1.4', row.names = c('1', '2', '3', '4'), class = 'data.frame')),     .Names = c('x', 'y'));do.call('identical', argv)
 [1] FALSE
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testidentical37#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testidentical37#
 #argv <- structure(list(x = structure(list(a = NA, b = NA_integer_,     c = NA_real_, d = NA_complex_, e = 1, f = 1L, g = 1:3, h = c(NA,         1L, 2L, 3L), i = NA_character_, j = c('foo', NA, 'bar')),     .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')),     y = structure(list(a = NA, b = NA_integer_, c = NA_real_,         d = NA_complex_, e = 1, f = 1L, g = 1:3, h = c(NA, 1L,             2L, 3L), i = NA_character_, j = c('foo', NA, 'bar')),         .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',             'j'))), .Names = c('x', 'y'));do.call('identical', argv)
 [1] TRUE
 
@@ -29260,7 +29296,7 @@ Error in lockEnvironment("foo", TRUE) : not an environment
 [1,] 0.00000 0.47712
 [2,] 0.30103 0.60206
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_log10.testLog10#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_log10.testLog10#
 #{ x <- c(a=1, b=10) ; round( c(log(x), log10(x), log2(x)), digits=5 ) }
       a       b       a       b       a       b
 0.00000 2.30259 0.00000 1.00000 0.00000 3.32193
@@ -39362,7 +39398,7 @@ complex(0)
 #argv <- list(c(1, 8, 28, 56, 70, 56, 28, 8, 1)); .Internal(polyroot(argv[[1]]))
 [1] -1-0i -1+0i -1+0i -1-0i -1-0i -1-0i -1-0i -1-0i
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty1#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty1#
 #argv <- list(0L, 3L, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))
 $l
 [1] 0
@@ -39374,7 +39410,7 @@ $n
 [1] 6
 
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty2#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty2#
 #argv <- list(-0.03, 1.11, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))
 $l
 [1] -0.2
@@ -39386,7 +39422,7 @@ $n
 [1] 7
 
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty3#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty3#
 #argv <- list(-6.64448090063514e-06, 6.64454021993011e-06, 1, 0, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))
 $l
 [1] -1e-05
@@ -39398,7 +39434,7 @@ $n
 [1] 2
 
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty4#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_pretty.testpretty4#
 #argv <- list(1.234e+100, 1.234e+100, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))
 $l
 [1] 1.2e+100
@@ -41158,6 +41194,186 @@ Error in rawShift(x = as.raw(c(0x00, 0x01, 0x20, 0x7f, 0x80, 0xff, 0x7b :
 Error in rawShift(x = as.raw(c(0x00, 0x01, 0x20, 0x7f, 0x80, 0xff, 0x7b :
   argument 'shift' must be a small integer
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits('a')
+Error in rawToBits("a") : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(01)
+Error in rawToBits(1) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(0:255)
+Error in rawToBits(0:255) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(NA)
+Error in rawToBits(NA) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(NULL)
+Error in rawToBits(NULL) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(as.raw(0))
+[1] 00 00 00 00 00 00 00 00
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(as.raw(0:255))
+   [1] 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00
+  [25] 01 01 00 00 00 00 00 00 00 00 01 00 00 00 00 00 01 00 01 00 00 00 00 00
+  [49] 00 01 01 00 00 00 00 00 01 01 01 00 00 00 00 00 00 00 00 01 00 00 00 00
+  [73] 01 00 00 01 00 00 00 00 00 01 00 01 00 00 00 00 01 01 00 01 00 00 00 00
+  [97] 00 00 01 01 00 00 00 00 01 00 01 01 00 00 00 00 00 01 01 01 00 00 00 00
+ [121] 01 01 01 01 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00
+ [145] 00 01 00 00 01 00 00 00 01 01 00 00 01 00 00 00 00 00 01 00 01 00 00 00
+ [169] 01 00 01 00 01 00 00 00 00 01 01 00 01 00 00 00 01 01 01 00 01 00 00 00
+ [193] 00 00 00 01 01 00 00 00 01 00 00 01 01 00 00 00 00 01 00 01 01 00 00 00
+ [217] 01 01 00 01 01 00 00 00 00 00 01 01 01 00 00 00 01 00 01 01 01 00 00 00
+ [241] 00 01 01 01 01 00 00 00 01 01 01 01 01 00 00 00 00 00 00 00 00 01 00 00
+ [265] 01 00 00 00 00 01 00 00 00 01 00 00 00 01 00 00 01 01 00 00 00 01 00 00
+ [289] 00 00 01 00 00 01 00 00 01 00 01 00 00 01 00 00 00 01 01 00 00 01 00 00
+ [313] 01 01 01 00 00 01 00 00 00 00 00 01 00 01 00 00 01 00 00 01 00 01 00 00
+ [337] 00 01 00 01 00 01 00 00 01 01 00 01 00 01 00 00 00 00 01 01 00 01 00 00
+ [361] 01 00 01 01 00 01 00 00 00 01 01 01 00 01 00 00 01 01 01 01 00 01 00 00
+ [385] 00 00 00 00 01 01 00 00 01 00 00 00 01 01 00 00 00 01 00 00 01 01 00 00
+ [409] 01 01 00 00 01 01 00 00 00 00 01 00 01 01 00 00 01 00 01 00 01 01 00 00
+ [433] 00 01 01 00 01 01 00 00 01 01 01 00 01 01 00 00 00 00 00 01 01 01 00 00
+ [457] 01 00 00 01 01 01 00 00 00 01 00 01 01 01 00 00 01 01 00 01 01 01 00 00
+ [481] 00 00 01 01 01 01 00 00 01 00 01 01 01 01 00 00 00 01 01 01 01 01 00 00
+ [505] 01 01 01 01 01 01 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 00 01 00
+ [529] 00 01 00 00 00 00 01 00 01 01 00 00 00 00 01 00 00 00 01 00 00 00 01 00
+ [553] 01 00 01 00 00 00 01 00 00 01 01 00 00 00 01 00 01 01 01 00 00 00 01 00
+ [577] 00 00 00 01 00 00 01 00 01 00 00 01 00 00 01 00 00 01 00 01 00 00 01 00
+ [601] 01 01 00 01 00 00 01 00 00 00 01 01 00 00 01 00 01 00 01 01 00 00 01 00
+ [625] 00 01 01 01 00 00 01 00 01 01 01 01 00 00 01 00 00 00 00 00 01 00 01 00
+ [649] 01 00 00 00 01 00 01 00 00 01 00 00 01 00 01 00 01 01 00 00 01 00 01 00
+ [673] 00 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 00 01 01 00 01 00 01 00
+ [697] 01 01 01 00 01 00 01 00 00 00 00 01 01 00 01 00 01 00 00 01 01 00 01 00
+ [721] 00 01 00 01 01 00 01 00 01 01 00 01 01 00 01 00 00 00 01 01 01 00 01 00
+ [745] 01 00 01 01 01 00 01 00 00 01 01 01 01 00 01 00 01 01 01 01 01 00 01 00
+ [769] 00 00 00 00 00 01 01 00 01 00 00 00 00 01 01 00 00 01 00 00 00 01 01 00
+ [793] 01 01 00 00 00 01 01 00 00 00 01 00 00 01 01 00 01 00 01 00 00 01 01 00
+ [817] 00 01 01 00 00 01 01 00 01 01 01 00 00 01 01 00 00 00 00 01 00 01 01 00
+ [841] 01 00 00 01 00 01 01 00 00 01 00 01 00 01 01 00 01 01 00 01 00 01 01 00
+ [865] 00 00 01 01 00 01 01 00 01 00 01 01 00 01 01 00 00 01 01 01 00 01 01 00
+ [889] 01 01 01 01 00 01 01 00 00 00 00 00 01 01 01 00 01 00 00 00 01 01 01 00
+ [913] 00 01 00 00 01 01 01 00 01 01 00 00 01 01 01 00 00 00 01 00 01 01 01 00
+ [937] 01 00 01 00 01 01 01 00 00 01 01 00 01 01 01 00 01 01 01 00 01 01 01 00
+ [961] 00 00 00 01 01 01 01 00 01 00 00 01 01 01 01 00 00 01 00 01 01 01 01 00
+ [985] 01 01 00 01 01 01 01 00 00 00 01 01 01 01 01 00 01 00 01 01 01 01 01 00
+[1009] 00 01 01 01 01 01 01 00 01 01 01 01 01 01 01 00 00 00 00 00 00 00 00 01
+[1033] 01 00 00 00 00 00 00 01 00 01 00 00 00 00 00 01 01 01 00 00 00 00 00 01
+[1057] 00 00 01 00 00 00 00 01 01 00 01 00 00 00 00 01 00 01 01 00 00 00 00 01
+[1081] 01 01 01 00 00 00 00 01 00 00 00 01 00 00 00 01 01 00 00 01 00 00 00 01
+[1105] 00 01 00 01 00 00 00 01 01 01 00 01 00 00 00 01 00 00 01 01 00 00 00 01
+[1129] 01 00 01 01 00 00 00 01 00 01 01 01 00 00 00 01 01 01 01 01 00 00 00 01
+[1153] 00 00 00 00 01 00 00 01 01 00 00 00 01 00 00 01 00 01 00 00 01 00 00 01
+[1177] 01 01 00 00 01 00 00 01 00 00 01 00 01 00 00 01 01 00 01 00 01 00 00 01
+[1201] 00 01 01 00 01 00 00 01 01 01 01 00 01 00 00 01 00 00 00 01 01 00 00 01
+[1225] 01 00 00 01 01 00 00 01 00 01 00 01 01 00 00 01 01 01 00 01 01 00 00 01
+[1249] 00 00 01 01 01 00 00 01 01 00 01 01 01 00 00 01 00 01 01 01 01 00 00 01
+[1273] 01 01 01 01 01 00 00 01 00 00 00 00 00 01 00 01 01 00 00 00 00 01 00 01
+[1297] 00 01 00 00 00 01 00 01 01 01 00 00 00 01 00 01 00 00 01 00 00 01 00 01
+[1321] 01 00 01 00 00 01 00 01 00 01 01 00 00 01 00 01 01 01 01 00 00 01 00 01
+[1345] 00 00 00 01 00 01 00 01 01 00 00 01 00 01 00 01 00 01 00 01 00 01 00 01
+[1369] 01 01 00 01 00 01 00 01 00 00 01 01 00 01 00 01 01 00 01 01 00 01 00 01
+[1393] 00 01 01 01 00 01 00 01 01 01 01 01 00 01 00 01 00 00 00 00 01 01 00 01
+[1417] 01 00 00 00 01 01 00 01 00 01 00 00 01 01 00 01 01 01 00 00 01 01 00 01
+[1441] 00 00 01 00 01 01 00 01 01 00 01 00 01 01 00 01 00 01 01 00 01 01 00 01
+[1465] 01 01 01 00 01 01 00 01 00 00 00 01 01 01 00 01 01 00 00 01 01 01 00 01
+[1489] 00 01 00 01 01 01 00 01 01 01 00 01 01 01 00 01 00 00 01 01 01 01 00 01
+[1513] 01 00 01 01 01 01 00 01 00 01 01 01 01 01 00 01 01 01 01 01 01 01 00 01
+[1537] 00 00 00 00 00 00 01 01 01 00 00 00 00 00 01 01 00 01 00 00 00 00 01 01
+[1561] 01 01 00 00 00 00 01 01 00 00 01 00 00 00 01 01 01 00 01 00 00 00 01 01
+[1585] 00 01 01 00 00 00 01 01 01 01 01 00 00 00 01 01 00 00 00 01 00 00 01 01
+[1609] 01 00 00 01 00 00 01 01 00 01 00 01 00 00 01 01 01 01 00 01 00 00 01 01
+[1633] 00 00 01 01 00 00 01 01 01 00 01 01 00 00 01 01 00 01 01 01 00 00 01 01
+[1657] 01 01 01 01 00 00 01 01 00 00 00 00 01 00 01 01 01 00 00 00 01 00 01 01
+[1681] 00 01 00 00 01 00 01 01 01 01 00 00 01 00 01 01 00 00 01 00 01 00 01 01
+[1705] 01 00 01 00 01 00 01 01 00 01 01 00 01 00 01 01 01 01 01 00 01 00 01 01
+[1729] 00 00 00 01 01 00 01 01 01 00 00 01 01 00 01 01 00 01 00 01 01 00 01 01
+[1753] 01 01 00 01 01 00 01 01 00 00 01 01 01 00 01 01 01 00 01 01 01 00 01 01
+[1777] 00 01 01 01 01 00 01 01 01 01 01 01 01 00 01 01 00 00 00 00 00 01 01 01
+[1801] 01 00 00 00 00 01 01 01 00 01 00 00 00 01 01 01 01 01 00 00 00 01 01 01
+[1825] 00 00 01 00 00 01 01 01 01 00 01 00 00 01 01 01 00 01 01 00 00 01 01 01
+[1849] 01 01 01 00 00 01 01 01 00 00 00 01 00 01 01 01 01 00 00 01 00 01 01 01
+[1873] 00 01 00 01 00 01 01 01 01 01 00 01 00 01 01 01 00 00 01 01 00 01 01 01
+[1897] 01 00 01 01 00 01 01 01 00 01 01 01 00 01 01 01 01 01 01 01 00 01 01 01
+[1921] 00 00 00 00 01 01 01 01 01 00 00 00 01 01 01 01 00 01 00 00 01 01 01 01
+[1945] 01 01 00 00 01 01 01 01 00 00 01 00 01 01 01 01 01 00 01 00 01 01 01 01
+[1969] 00 01 01 00 01 01 01 01 01 01 01 00 01 01 01 01 00 00 00 01 01 01 01 01
+[1993] 01 00 00 01 01 01 01 01 00 01 00 01 01 01 01 01 01 01 00 01 01 01 01 01
+[2017] 00 00 01 01 01 01 01 01 01 00 01 01 01 01 01 01 00 01 01 01 01 01 01 01
+[2041] 01 01 01 01 01 01 01 01
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(as.raw(1))
+[1] 01 00 00 00 00 00 00 00
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(as.raw(1)[1])
+[1] 01 00 00 00 00 00 00 00
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(as.raw(255))
+[1] 01 01 01 01 01 01 01 01
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(as.raw(c(0,1,255)))
+ [1] 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(c(NULL))
+Error in rawToBits(c(NULL)) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(c(as.raw(1), as.raw(255)))
+ [1] 01 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(double(0))
+Error in rawToBits(double(0)) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(environment)
+Error in rawToBits(environment) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(integer(0))
+Error in rawToBits(integer(0)) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(list(NULL))
+Error in rawToBits(list(NULL)) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(list(list()))
+Error in rawToBits(list(list())) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(new.env())
+Error in rawToBits(new.env()) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(raw(0))
+raw(0)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(raw(0), raw(1))
+Error in rawToBits(raw(0), raw(1)) : unused argument (raw(1))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(raw(10))
+ [1] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[26] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[51] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[76] 00 00 00 00 00
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToBits.testRawToBits#
+#rawToBits(stdout())
+Error in rawToBits(stdout()) : argument 'x' must be a raw vector
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rawToChar.testrawToChar1#
 #argv <- structure(list(x = as.raw(c(115, 116, 114, 105, 110,     103))), .Names = 'x');do.call('rawToChar', argv)
 [1] "string"
@@ -45739,6 +45955,54 @@ integer(0)
 #argv <- list(29);sign(argv[[1]]);
 [1] 1
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign('1')
+Error in sign("1") : non-numeric argument to mathematical function
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign('1L')
+Error in sign("1L") : non-numeric argument to mathematical function
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign('a')
+Error in sign("a") : non-numeric argument to mathematical function
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(1i)
+Error in sign(0+1i) : unimplemented complex function
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(NA_real_)
+[1] NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(NULL)
+Error in sign(NULL) : non-numeric argument to mathematical function
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(NaN)
+[1] NaN
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(c(1, -1, FALSE))
+[1]  1 -1  0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(c(1, -1, FALSE, 1i))
+Error in sign(c(1, -1, FALSE, 0+1i)) : unimplemented complex function
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(c(FALSE))
+[1] 0
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(c(FALSE, TRUE))
+[1] 0 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign10#
+#sign(list(c(1, -1, FALSE))[[1]])
+[1]  1 -1  0
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_sign.testsign2#
 #argv <- list(-29);sign(argv[[1]]);
 [1] -1
@@ -113686,6 +113950,38 @@ Warning message:
 In rgamma(30, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0,  :
   NAs produced
 
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#Output.IgnoreWhitespace#
+#set.seed(1); rlnorm(10, 10, 10)
+ [1] 4.190738e+01 1.381967e+05 5.174351e+00 1.867073e+11 5.942633e+05
+ [6] 6.021378e+00 2.882852e+06 3.543629e+07 6.974795e+06 1.039106e+03
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#Output.IgnoreWhitespace#
+#set.seed(1); rlnorm(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3))
+ [1]         NaN   1.0000000   1.1472349   8.7170336   1.6374074         NaN
+ [7] 148.4131591   0.4315068   1.3452192   0.1042040         NaN  20.0855369
+[13]  57.3253483 288.4414833   2.0695766         NaN   1.2214028   7.1668137
+[19]  78.3043417 175.8321258
+Warning message:
+In rlnorm(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#Output.IgnoreWhitespace#
+#set.seed(1); rlnorm(24, c(0.0653, 0.000123, 32e-80, 8833, 79e70), c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1))
+ [1] 1.0246925 1.0001456 1.0000000       Inf       Inf 1.0674792       NaN
+ [8] 0.9478333       Inf       Inf       Inf 0.0000000 1.0000000       NaN
+[15]       Inf 1.0675304 1.0001230 0.0000000       Inf       Inf       NaN
+[22] 0.9971928 0.9999980       Inf
+Warning message:
+In rlnorm(24, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71), c(0.0653,  :
+  NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#Output.IgnoreWhitespace#
+#set.seed(1); rlnorm(30, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0))
+ [1] NaN NaN NaN Inf NaN NaN NaN NaN NaN   0 NaN NaN NaN NaN NaN NaN NaN NaN NaN
+[20] NaN NaN   1 NaN NaN NaN NaN NaN NaN NaN NaN
+Warning message:
+In rlnorm(30, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0,  :
+  NAs produced
+
 ##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#Output.IgnoreWhitespace#
 #set.seed(1); rlogis(10, 10, 10)
  [1]  -0.1753073   4.7688401  12.9350241  32.9194576  -3.7581524  31.7945887
@@ -113954,6 +114250,1707 @@ B    5    8    4    7    6    2    6
 [2,]    2    0    0    1    0
 [3,]    1    2    3    2    3
 
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dchisq(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] Inf Inf Inf   0   0 Inf NaN
+Warning message:
+In dchisq(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dchisq(10, 10, log=TRUE)
+[1] -2.433449
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dchisq(3, 3, log=FALSE)
+[1] 0.1541803
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=FALSE)
+ [1]         NaN         Inf 0.207096473 0.093458828 0.000000000         NaN
+ [7] 0.000000000 0.009447299 0.000000000 0.000000000         NaN 0.000000000
+[13] 0.000000000         Inf 0.161434226         NaN 0.000000000         Inf
+[19] 0.815615297 0.207553749
+Warning message:
+In dchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=TRUE)
+ [1]        NaN        Inf -1.5745705 -2.3702343       -Inf        NaN
+ [7]       -Inf -4.6620264       -Inf       -Inf        NaN       -Inf
+[13]       -Inf        Inf -1.8236575        NaN       -Inf        Inf
+[19] -0.2038125 -1.5723649
+Warning message:
+In dchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dchisq(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log=FALSE)
+ [1]  NA Inf NaN   0   0  NA Inf NaN   0   0  NA Inf NaN   0   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] 6.530e-02 1.230e-04 3.200e-79 8.833e+03 7.900e+71 0.000e+00       NaN
+Warning message:
+In dexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dexp(10, 10, log=TRUE)
+[1] -97.69741
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dexp(3, 3, log=FALSE)
+[1] 0.0003702294
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=FALSE)
+ [1]         NaN 0.000000000 0.098019867 0.148768999 0.000000000         NaN
+ [7] 0.000000000 0.081873075 0.000000000 3.000000000         NaN 0.000000000
+[13] 0.000000000 0.900000000 1.646434908         NaN 0.000000000 0.100000000
+[19] 0.751743190 0.007436257
+Warning message:
+In dexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=TRUE)
+ [1]        NaN       -Inf -2.3225851 -1.9053605       -Inf        NaN
+ [7]       -Inf -2.5025851       -Inf  1.0986123        NaN       -Inf
+[13]       -Inf -0.1053605  0.4986123        NaN       -Inf -2.3025851
+[19] -0.2853605 -4.9013877
+Warning message:
+In dexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dexp(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log=FALSE)
+ [1]  NA 0.0 NaN 0.0 0.0  NA 1.0 NaN 0.0 0.0  NA 0.1 NaN NaN 0.0
+Warning message:
+In dexp(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dgeom(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] 6.53e-02 1.23e-04 3.20e-79      NaN      NaN      NaN      NaN
+Warning message:
+In dgeom(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dgeom(10, 10, log=TRUE)
+[1] NaN
+Warning message:
+In dgeom(10, 10, log = TRUE) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dgeom(3, 3, log=FALSE)
+[1] NaN
+Warning message:
+In dgeom(3, 3, log = FALSE) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=FALSE)
+ [1]   NaN   NaN 0.000 0.009   NaN   NaN   NaN 0.081 0.000   NaN   NaN   NaN
+[13] 0.000 0.900   NaN   NaN   NaN 0.100 0.000   NaN
+Warning messages:
+1: In dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  non-integer x = 0.200000
+2: In dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  non-integer x = 0.200000
+3: In dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=TRUE)
+ [1]        NaN        NaN       -Inf -4.7105307        NaN        NaN
+ [7]        NaN -2.5133061       -Inf        NaN        NaN        NaN
+[13]       -Inf -0.1053605        NaN        NaN        NaN -2.3025851
+[19]       -Inf        NaN
+Warning messages:
+1: In dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  non-integer x = 0.200000
+2: In dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  non-integer x = 0.200000
+3: In dgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dgeom(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log=FALSE)
+ [1]  NA NaN NaN 0.0 NaN  NA 1.0 NaN 0.0 0.0  NA 0.1 NaN NaN 0.0
+Warning message:
+In dgeom(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dpois(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] 0.9367864 0.9998770 1.0000000 0.0000000 0.0000000 1.0000000       NaN
+Warning message:
+In dpois(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dpois(10, 10, log=TRUE)
+[1] -2.078562
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dpois(3, 3, log=FALSE)
+[1] 0.2240418
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=FALSE)
+ [1]         NaN 1.000000000 0.000000000 0.164660712 0.000000000         NaN
+ [7] 0.000000000 0.004524187 0.000000000 0.049787068         NaN 0.000000000
+[13] 0.000000000 0.406569660 0.000000000         NaN 0.000000000 0.904837418
+[19] 0.000000000 0.224041808
+Warning messages:
+1: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  non-integer x = 0.200000
+2: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  non-integer x = 0.200000
+3: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  non-integer x = 0.200000
+4: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  non-integer x = 0.200000
+5: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=TRUE)
+ [1]       NaN  0.000000      -Inf -1.803868      -Inf       NaN      -Inf
+ [8] -5.398317      -Inf -3.000000       NaN      -Inf      -Inf -0.900000
+[15]      -Inf       NaN      -Inf -0.100000      -Inf -1.495923
+Warning messages:
+1: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  non-integer x = 0.200000
+2: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  non-integer x = 0.200000
+3: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  non-integer x = 0.200000
+4: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  non-integer x = 0.200000
+5: In dpois(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dpois(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log=FALSE)
+ [1]        NA 1.0000000       NaN 0.0000000 0.0000000        NA 0.3678794
+ [8]       NaN 0.0000000 0.0000000        NA 0.9048374       NaN 0.0000000
+[15] 0.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dt(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] 1.223197e-01 5.544796e-03 2.828427e-40 3.989310e-01 3.989423e-01
+[6]          NaN          NaN
+Warning message:
+In dt(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dt(10, 10, log=TRUE)
+[1] -14.13232
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dt(3, 3, log=FALSE)
+[1] 0.02297204
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dt(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=FALSE)
+ [1]        NaN        NaN 0.12307265 0.06230778 0.20674834        NaN
+ [7]        NaN 0.01920883 0.15325430 0.36755260        NaN        NaN
+[13] 0.03960646 0.31167229 0.35794379        NaN        NaN 0.14809212
+[19] 0.29905916 0.06750966
+Warning message:
+In dt(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dt(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=TRUE)
+ [1]       NaN       NaN -2.094980 -2.775669 -1.576253       NaN       NaN
+ [8] -3.952385 -1.875657 -1.000889       NaN       NaN -3.228763 -1.165803
+[15] -1.027379       NaN       NaN -1.909921 -1.207114 -2.695485
+Warning message:
+In dt(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log = TRUE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions21#Output.IgnoreWhitespace#
+#set.seed(1); dt(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log=FALSE)
+ [1]        NA       NaN       NaN 0.0000000       NaN        NA 0.3183099
+ [8]       NaN 0.0000000 0.0000000        NA 0.1480921       NaN       NaN
+[15] 0.0000000
+Warning message:
+In dt(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log = FALSE) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, 10, lower.tail=FALSE, log.p=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, 10, lower.tail=FALSE, log.p=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, 10, lower.tail=TRUE, log.p=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, 10, lower.tail=TRUE, log.p=TRUE)
+[1] -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=FALSE)
+[1]   1   1   1   1   1   1 NaN
+Warning message:
+In pchisq(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=TRUE)
+[1]   0   0   0   0   0   0 NaN
+Warning message:
+In pchisq(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=FALSE)
+[1]   0   0   0   0   0   0 NaN
+Warning message:
+In pchisq(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=TRUE)
+[1] -Inf -Inf -Inf -Inf -Inf -Inf  NaN
+Warning message:
+In pchisq(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=FALSE)
+ [1]        NaN 1.00000000 0.08874237 0.13808560 1.00000000        NaN
+ [7] 0.00000000 0.01152365 1.00000000 1.00000000        NaN 0.00000000
+[13] 1.00000000 1.00000000 0.97758930        NaN 1.00000000 1.00000000
+[19] 0.61145396 0.57240670
+Warning message:
+In pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=TRUE)
+ [1]         NaN  0.00000000 -2.42201777 -1.97988153  0.00000000         NaN
+ [7]        -Inf -4.46335358  0.00000000  0.00000000         NaN        -Inf
+[13]  0.00000000  0.00000000 -0.02266564         NaN  0.00000000  0.00000000
+[19] -0.49191562 -0.55790552
+Warning message:
+In pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=FALSE)
+ [1]       NaN 0.0000000 0.9112576 0.8619144 0.0000000       NaN 1.0000000
+ [8] 0.9884763 0.0000000 0.0000000       NaN 1.0000000 0.0000000 0.0000000
+[15] 0.0224107       NaN 0.0000000 0.0000000 0.3885460 0.4275933
+Warning message:
+In pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=TRUE)
+ [1]         NaN        -Inf -0.09292963 -0.14859931        -Inf         NaN
+ [7]  0.00000000 -0.01159056        -Inf        -Inf         NaN  0.00000000
+[13]        -Inf        -Inf -3.79821666         NaN        -Inf        -Inf
+[19] -0.94534361 -0.84958278
+Warning message:
+In pchisq(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]  NA   0 NaN   1   0  NA   0 NaN   1   0  NA   0 NaN   1   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pchisq(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]  NA   0 NaN NaN NaN  NA   1 NaN NaN NaN  NA   1 NaN   0 NaN
+Warning messages:
+1: In pchisq(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0)) :
+  value out of range in 'lgamma'
+2: In pchisq(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0)) :
+  value out of range in 'lgamma'
+3: In pchisq(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0)) :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, 10, lower.tail=FALSE, log.p=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, 10, lower.tail=FALSE, log.p=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, 10, lower.tail=TRUE, log.p=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, 10, lower.tail=TRUE, log.p=TRUE)
+[1] -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=FALSE)
+[1]   1   1   1   1   1   1 NaN
+Warning message:
+In pexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=TRUE)
+[1]   0   0   0   0   0   0 NaN
+Warning message:
+In pexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=FALSE)
+[1]   0   0   0   0   0   0 NaN
+Warning message:
+In pexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=TRUE)
+[1] -Inf -Inf -Inf -Inf -Inf -Inf  NaN
+Warning message:
+In pexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=FALSE)
+ [1]         NaN 1.000000000 0.980198673 0.165298888 1.000000000         NaN
+ [7] 1.000000000 0.818730753 1.000000000 1.000000000         NaN 1.000000000
+[13] 1.000000000 1.000000000 0.548811636         NaN 1.000000000 1.000000000
+[19] 0.835270211 0.002478752
+Warning message:
+In pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=TRUE)
+ [1]   NaN  0.00 -0.02 -1.80  0.00   NaN  0.00 -0.20  0.00  0.00   NaN  0.00
+[13]  0.00  0.00 -0.60   NaN  0.00  0.00 -0.18 -6.00
+Warning message:
+In pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=FALSE)
+ [1]        NaN 0.00000000 0.01980133 0.83470111 0.00000000        NaN
+ [7] 0.00000000 0.18126925 0.00000000 0.00000000        NaN 0.00000000
+[13] 0.00000000 0.00000000 0.45118836        NaN 0.00000000 0.00000000
+[19] 0.16472979 0.99752125
+Warning message:
+In pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=TRUE)
+ [1]          NaN         -Inf -3.922006339 -0.180681568         -Inf
+ [6]          NaN         -Inf -1.707771801         -Inf         -Inf
+[11]          NaN         -Inf         -Inf         -Inf -0.795870368
+[16]          NaN         -Inf         -Inf -1.803448792 -0.002481829
+Warning message:
+In pexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]  NA   0 NaN   1   0  NA   0 NaN   1   0  NA   0 NaN NaN   0
+Warning message:
+In pexp(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5)) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); pexp(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]   NA    0  NaN    1    0   NA    0  NaN    1 -Inf   NA    0  NaN    0 -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, 10, lower.tail=FALSE, log.p=FALSE)
+[1] Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, 10, lower.tail=FALSE, log.p=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, 10, lower.tail=TRUE, log.p=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, 10, lower.tail=TRUE, log.p=TRUE)
+[1] Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=FALSE)
+[1] Inf Inf Inf Inf Inf Inf NaN
+Warning message:
+In qexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=TRUE)
+[1]   0   0   0   0   0   0 NaN
+Warning message:
+In qexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=FALSE)
+[1]   0   0   0   0   0   0 NaN
+Warning message:
+In qexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=TRUE)
+[1] Inf Inf Inf Inf Inf Inf NaN
+Warning message:
+In qexp(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=FALSE)
+ [1]        NaN        Inf 16.0943791        NaN        NaN        NaN
+ [7]        Inf        NaN        NaN        Inf        NaN        NaN
+[13]        NaN        Inf  0.5364793        NaN        NaN        Inf
+[19]  1.7882643        NaN
+Warning message:
+In qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=TRUE)
+ [1]        NaN  0.0000000        NaN        NaN  0.3333333        NaN
+ [7]        NaN        NaN  1.1111111  0.0000000        NaN        NaN
+[13] 10.0000000  0.0000000        NaN        NaN        Inf  0.0000000
+[19]        NaN        NaN
+Warning message:
+In qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=FALSE)
+ [1]        NaN 0.00000000 2.23143551        NaN        NaN        NaN
+ [7]        Inf        NaN        NaN 0.00000000        NaN        NaN
+[13]        NaN 0.00000000 0.07438118        NaN        NaN 0.00000000
+[19] 0.24793728        NaN
+Warning message:
+In qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=TRUE)
+ [1]       NaN       Inf       NaN       NaN 0.1528917       NaN       NaN
+ [8]       NaN 0.5096391       Inf       NaN       NaN 4.5867515       Inf
+[15]       NaN       NaN       Inf       Inf       NaN       NaN
+Warning message:
+In qexp(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]  NA   0 NaN NaN NaN  NA   0 NaN NaN NaN  NA   0 NaN NaN NaN
+Warning message:
+In qexp(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5)) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qexp(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]  NA   0 NaN NaN   0  NA Inf NaN   0 NaN  NA Inf NaN   0   0
+Warning message:
+In qexp(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0)) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, 10, lower.tail=FALSE, log.p=FALSE)
+[1] NaN
+Warning message:
+In qgeom(0, 10, lower.tail = FALSE, log.p = FALSE) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, 10, lower.tail=FALSE, log.p=TRUE)
+[1] NaN
+Warning message:
+In qgeom(0, 10, lower.tail = FALSE, log.p = TRUE) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, 10, lower.tail=TRUE, log.p=FALSE)
+[1] NaN
+Warning message:
+In qgeom(0, 10, lower.tail = TRUE, log.p = FALSE) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, 10, lower.tail=TRUE, log.p=TRUE)
+[1] NaN
+Warning message:
+In qgeom(0, 10, lower.tail = TRUE, log.p = TRUE) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=FALSE)
+[1] Inf Inf Inf NaN NaN NaN NaN
+Warning message:
+In qgeom(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=FALSE, log.p=TRUE)
+[1]   0   0   0 NaN NaN NaN NaN
+Warning message:
+In qgeom(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=FALSE)
+[1]   0   0   0 NaN NaN NaN NaN
+Warning message:
+In qgeom(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), lower.tail=TRUE, log.p=TRUE)
+[1] Inf Inf Inf NaN NaN NaN NaN
+Warning message:
+In qgeom(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=FALSE)
+ [1] NaN NaN  15 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN Inf NaN NaN NaN Inf   0
+[20] NaN
+Warning message:
+In qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=FALSE, log.p=TRUE)
+ [1] NaN NaN NaN NaN NaN NaN NaN NaN   0 NaN NaN NaN   9   0 NaN NaN NaN   0 NaN
+[20] NaN
+Warning message:
+In qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = FALSE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=FALSE)
+ [1] NaN NaN   2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN   0 NaN NaN NaN   0   0
+[20] NaN
+Warning message:
+In qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail=TRUE, log.p=TRUE)
+ [1] NaN NaN NaN NaN NaN NaN NaN NaN   0 NaN NaN NaN   4 Inf NaN NaN NaN Inf NaN
+[20] NaN
+Warning message:
+In qgeom(c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), lower.tail = TRUE,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]  NA NaN NaN NaN NaN  NA   0 NaN NaN NaN  NA   0 NaN NaN NaN
+Warning message:
+In qgeom(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5)) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions22#Output.IgnoreWhitespace#
+#set.seed(1); qgeom(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]  NA NaN NaN NaN NaN  NA NaN NaN NaN NaN  NA NaN NaN NaN NaN
+Warning message:
+In qgeom(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0)) : NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dbeta(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70), c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] Inf Inf Inf   0   0   0 NaN
+Warning message:
+In dbeta(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71), c(0.0653,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dbeta(0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0), log=FALSE)
+[1]  NA NaN  NA   0 NaN  NA
+Warning message:
+In dbeta(0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dbeta(10, 10, 10, log=TRUE)
+[1] -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dbeta(3, 3, 3, log=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dbeta(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=FALSE)
+ [1] NaN Inf Inf   0   0 NaN   0 NaN   0   0 NaN Inf   0   0 NaN NaN   0 Inf   0
+[20]   0 NaN NaN Inf Inf   0 NaN Inf   0 NaN   0 NaN   0 Inf   0   0 NaN   0 Inf
+[39] Inf   0 NaN Inf NaN Inf   0 NaN   0 Inf   0 NaN NaN   0   0 Inf   0 NaN NaN
+[58]   0 Inf   0
+Warning message:
+In dbeta(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dbeta(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=TRUE)
+ [1]  NaN  Inf  Inf -Inf -Inf  NaN -Inf  NaN -Inf -Inf  NaN  Inf -Inf -Inf  NaN
+[16]  NaN -Inf  Inf -Inf -Inf  NaN  NaN  Inf  Inf -Inf  NaN  Inf -Inf  NaN -Inf
+[31]  NaN -Inf  Inf -Inf -Inf  NaN -Inf  Inf  Inf -Inf  NaN  Inf  NaN  Inf -Inf
+[46]  NaN -Inf  Inf -Inf  NaN  NaN -Inf -Inf  Inf -Inf  NaN  NaN -Inf  Inf -Inf
+Warning message:
+In dbeta(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dbeta(c(NA, NaN, 1/0, -1/0), 2, 2, log=FALSE)
+[1]  NA NaN   0   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70), c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] 2.437289e+00 1.293943e+03 4.973592e+77 1.801822e-05 2.014620e-73
+[6]          NaN          NaN
+Warning message:
+In dcauchy(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71), c(0.0653,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dcauchy(0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0), log=FALSE)
+[1]  NA NaN  NA NaN NaN  NA
+Warning message:
+In dcauchy(0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dcauchy(10, 10, 10, log=TRUE)
+[1] -3.447315
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dcauchy(3, 3, 3, log=FALSE)
+[1] 0.1061033
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dcauchy(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=FALSE)
+ [1]          NaN          NaN 0.0489707517 0.0292027419 0.0530516477
+ [6]          NaN          NaN 0.0315158303 0.1582756340 0.0914683581
+[11]          NaN          NaN 0.0012727305 0.0110995311 0.0734561276
+[16]          NaN          NaN 0.0315158303 0.0170421712 0.0381971863
+[21]          NaN          NaN 3.1830988618 0.1975716535 0.0530516477
+[26]          NaN          NaN 0.0008839486 0.1582756340 0.0954929659
+[31]          NaN          NaN 0.0079379024 0.0110995311 0.0280861664
+[36]          NaN          NaN 0.6366197724 0.1582756340 0.0381971863
+[41]          NaN          NaN 3.1830988618 0.3536776513 0.0990590932
+[46]          NaN          NaN 0.0035328511 0.0077826378 0.0954929659
+[51]          NaN          NaN 0.0079379024 0.0595590224 0.0280861664
+[56]          NaN          NaN 0.0315158303 0.3370339971 0.0954929659
+Warning message:
+In dcauchy(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dcauchy(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=TRUE)
+ [1]        NaN        NaN -3.0165321 -3.5334927 -2.9364894        NaN
+ [7]        NaN -3.4572653 -1.8434172 -2.3917622        NaN        NaN
+[13] -6.6665907 -4.5008524 -2.6110670        NaN        NaN -3.4572653
+[19] -4.0720643 -3.2649934        NaN        NaN  1.1578552 -1.6216540
+[25] -2.9364894        NaN        NaN -7.0311117 -1.8434172 -2.3487027
+[31]        NaN        NaN -4.8361062 -4.5008524 -3.5724781        NaN
+[37]        NaN -0.4515827 -1.8434172 -3.2649934        NaN        NaN
+[43]  1.1578552 -1.0393694 -2.3120387        NaN        NaN -5.6456501
+[49] -4.8558599 -2.3487027        NaN        NaN -4.8361062 -2.8207875
+[55] -3.5724781        NaN        NaN -3.4572653 -1.0875715 -2.3487027
+Warning message:
+In dcauchy(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dcauchy(c(NA, NaN, 1/0, -1/0), 2, 2, log=FALSE)
+[1]  NA NaN   0   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dgamma(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70), c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1] Inf Inf Inf   0   0 Inf NaN
+Warning message:
+In dgamma(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71), c(0.0653,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dgamma(0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0), log=FALSE)
+[1]  NA NaN  NA   0 NaN  NA
+Warning message:
+In dgamma(0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dgamma(10, 10, 10, log=TRUE)
+[1] -69.05271
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dgamma(3, 3, 3, log=FALSE)
+[1] 0.01499429
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dgamma(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=FALSE)
+ [1]          NaN          Inf 1.243592e-01 0.000000e+00 0.000000e+00
+ [6]          NaN 0.000000e+00          NaN 0.000000e+00 0.000000e+00
+[11]          NaN 0.000000e+00 0.000000e+00 0.000000e+00          NaN
+[16]          NaN          Inf 9.048374e-03 0.000000e+00 0.000000e+00
+[21]          NaN          NaN          Inf 8.671435e-02 0.000000e+00
+[26]          NaN 0.000000e+00 0.000000e+00          NaN 0.000000e+00
+[31]          NaN 0.000000e+00 4.524187e-04 0.000000e+00 0.000000e+00
+[36]          NaN 0.000000e+00          Inf 3.293214e-01 0.000000e+00
+[41]          NaN 0.000000e+00          NaN          Inf 1.350978e-02
+[46]          NaN 0.000000e+00 1.508062e-05 0.000000e+00          NaN
+[51]          NaN 0.000000e+00 0.000000e+00 1.481946e-01 0.000000e+00
+[56]          NaN          NaN 0.000000e+00          Inf 4.480836e-01
+Warning message:
+In dgamma(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dgamma(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=TRUE)
+ [1]         NaN         Inf  -2.0845808        -Inf        -Inf         NaN
+ [7]        -Inf         NaN        -Inf        -Inf         NaN        -Inf
+[13]        -Inf        -Inf         NaN         NaN         Inf  -4.7051702
+[19]        -Inf        -Inf         NaN         NaN         Inf  -2.4451359
+[25]        -Inf         NaN        -Inf        -Inf         NaN        -Inf
+[31]         NaN        -Inf  -7.7009025        -Inf        -Inf         NaN
+[37]        -Inf         Inf  -1.1107210        -Inf         NaN        -Inf
+[43]         NaN         Inf  -4.3043414         NaN        -Inf -11.1020998
+[49]        -Inf         NaN         NaN        -Inf        -Inf  -1.9092287
+[55]        -Inf         NaN         NaN        -Inf         Inf  -0.8027754
+Warning message:
+In dgamma(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dgamma(c(NA, NaN, 1/0, -1/0), 2, 2, log=FALSE)
+[1]  NA NaN   0   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dlnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70), c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE)
+[1]   0   0   0   0   0   0 NaN
+Warning message:
+In dlnorm(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71), c(0.0653,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dlnorm(0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0), log=FALSE)
+[1]  NA NaN  NA   0   0  NA
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dlnorm(10, 10, 10, log=TRUE)
+[1] -5.82036
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dlnorm(3, 3, 3, log=FALSE)
+[1] 0.03626103
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dlnorm(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=FALSE)
+ [1]           NaN  0.000000e+00  5.399097e-01  0.000000e+00  0.000000e+00
+ [6]           NaN  0.000000e+00  0.000000e+00  4.432692e-01  0.000000e+00
+[11]           NaN  0.000000e+00  0.000000e+00  0.000000e+00  1.257944e-01
+[16]           NaN  0.000000e+00  5.520948e-87  0.000000e+00  0.000000e+00
+[21]           NaN  0.000000e+00  0.000000e+00  4.324583e-01  0.000000e+00
+[26]           NaN  0.000000e+00  0.000000e+00  0.000000e+00  1.329808e-01
+[31]           NaN  0.000000e+00 1.473646e-195  0.000000e+00  0.000000e+00
+[36]           NaN  0.000000e+00  0.000000e+00  3.752628e-02  0.000000e+00
+[41]           NaN  0.000000e+00  0.000000e+00  0.000000e+00  1.326856e-01
+[46]           NaN  0.000000e+00  0.000000e+00  0.000000e+00  0.000000e+00
+[51]           NaN  0.000000e+00  0.000000e+00  1.713643e-03  0.000000e+00
+[56]           NaN  0.000000e+00  0.000000e+00  0.000000e+00  1.064827e-01
+Warning message:
+In dlnorm(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dlnorm(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=TRUE)
+ [1]          NaN         -Inf   -0.6163534         -Inf         -Inf
+ [6]          NaN         -Inf         -Inf   -0.8135780         -Inf
+[11]          NaN         -Inf         -Inf         -Inf   -2.0731064
+[16]          NaN         -Inf -198.6163534         -Inf         -Inf
+[21]          NaN         -Inf         -Inf   -0.8382694         -Inf
+[26]          NaN         -Inf         -Inf         -Inf   -2.0175508
+[31]          NaN         -Inf -448.6163534         -Inf         -Inf
+[36]          NaN         -Inf         -Inf   -3.2827138         -Inf
+[41]          NaN         -Inf         -Inf         -Inf   -2.0197730
+[46]          NaN         -Inf -798.6163534         -Inf         -Inf
+[51]          NaN         -Inf         -Inf   -6.3691336         -Inf
+[56]          NaN         -Inf         -Inf         -Inf   -2.2397730
+Warning message:
+In dlnorm(c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions31#Output.IgnoreWhitespace#
+#set.seed(1); dlnorm(c(NA, NaN, 1/0, -1/0), 2, 2, log=FALSE)
+[1]  NA NaN   0   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, 10, 10, lower.tail=FALSE, log.p=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, 10, 10, lower.tail=FALSE, log.p=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, 10, 10, lower.tail=TRUE, log.p=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, 10, 10, lower.tail=TRUE, log.p=TRUE)
+[1] -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=FALSE)
+ [1]   1   1   1   1   1   1 NaN   1   1   1   1   1   1 NaN   1   1   1   1   1
+[20]   1 NaN   1   1   1   1   1   1 NaN   1   1   1   1   1   1 NaN
+Warning message:
+In pbeta(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=TRUE)
+ [1]   0   0   0   0   0   0 NaN   0   0   0   0   0   0 NaN   0   0   0   0   0
+[20]   0 NaN   0   0   0   0   0   0 NaN   0   0   0   0   0   0 NaN
+Warning message:
+In pbeta(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=FALSE)
+ [1]   0   0   0   0   0   0 NaN   0   0   0   0   0   0 NaN   0   0   0   0   0
+[20]   0 NaN   0   0   0   0   0   0 NaN   0   0   0   0   0   0 NaN
+Warning message:
+In pbeta(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=TRUE)
+ [1] -Inf -Inf -Inf -Inf -Inf -Inf  NaN -Inf -Inf -Inf -Inf -Inf -Inf  NaN -Inf
+[16] -Inf -Inf -Inf -Inf -Inf  NaN -Inf -Inf -Inf -Inf -Inf -Inf  NaN -Inf -Inf
+[31] -Inf -Inf -Inf -Inf  NaN
+Warning message:
+In pbeta(0, c(0.0653, 0.000123, 3.2e-79, 8833, 7.9e+71, 0, -1),  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=FALSE)
+  [1]       NaN 1.0000000 0.1486601 0.0000000       NaN       NaN       NaN
+  [8] 0.0000000 1.0000000 1.0000000       NaN 0.0000000       NaN 1.0000000
+ [15] 0.9920000       NaN       NaN 1.0000000       NaN 0.0000000       NaN
+ [22] 1.0000000       NaN 0.0000000       NaN       NaN 0.0000000 0.0000000
+ [29]       NaN 1.0000000       NaN 0.0000000 1.0000000 1.0000000       NaN
+ [36]       NaN       NaN 1.0000000 0.7650762 0.0000000       NaN 1.0000000
+ [43]       NaN 0.0000000 1.0000000       NaN       NaN 0.0000000       NaN
+ [50] 1.0000000       NaN 0.0000000       NaN 1.0000000       NaN       NaN
+ [57] 1.0000000 1.0000000       NaN 0.0000000       NaN 1.0000000 0.1486601
+ [64] 0.0000000       NaN       NaN       NaN 0.0000000 1.0000000 1.0000000
+ [71]       NaN 0.0000000       NaN 1.0000000 0.9920000       NaN       NaN
+ [78] 1.0000000       NaN 0.0000000       NaN 1.0000000       NaN 0.0000000
+ [85]       NaN       NaN 0.0000000 0.0000000       NaN 1.0000000       NaN
+ [92] 0.0000000 1.0000000 1.0000000       NaN       NaN       NaN 1.0000000
+ [99] 0.7650762 0.0000000       NaN 1.0000000       NaN 0.0000000 1.0000000
+[106]       NaN       NaN 0.0000000       NaN 1.0000000       NaN 0.0000000
+[113]       NaN 1.0000000       NaN       NaN 1.0000000 1.0000000       NaN
+[120] 0.0000000
+Warning message:
+In pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=TRUE)
+  [1]          NaN  0.000000000 -1.906092939         -Inf          NaN
+  [6]          NaN          NaN         -Inf  0.000000000  0.000000000
+ [11]          NaN         -Inf          NaN  0.000000000 -0.008032172
+ [16]          NaN          NaN  0.000000000          NaN         -Inf
+ [21]          NaN  0.000000000          NaN         -Inf          NaN
+ [26]          NaN         -Inf         -Inf          NaN  0.000000000
+ [31]          NaN         -Inf  0.000000000  0.000000000          NaN
+ [36]          NaN          NaN  0.000000000 -0.267779827         -Inf
+ [41]          NaN  0.000000000          NaN         -Inf  0.000000000
+ [46]          NaN          NaN         -Inf          NaN  0.000000000
+ [51]          NaN         -Inf          NaN  0.000000000          NaN
+ [56]          NaN  0.000000000  0.000000000          NaN         -Inf
+ [61]          NaN  0.000000000 -1.906092939         -Inf          NaN
+ [66]          NaN          NaN         -Inf  0.000000000  0.000000000
+ [71]          NaN         -Inf          NaN  0.000000000 -0.008032172
+ [76]          NaN          NaN  0.000000000          NaN         -Inf
+ [81]          NaN  0.000000000          NaN         -Inf          NaN
+ [86]          NaN         -Inf         -Inf          NaN  0.000000000
+ [91]          NaN         -Inf  0.000000000  0.000000000          NaN
+ [96]          NaN          NaN  0.000000000 -0.267779827         -Inf
+[101]          NaN  0.000000000          NaN         -Inf  0.000000000
+[106]          NaN          NaN         -Inf          NaN  0.000000000
+[111]          NaN         -Inf          NaN  0.000000000          NaN
+[116]          NaN  0.000000000  0.000000000          NaN         -Inf
+Warning message:
+In pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=FALSE)
+  [1]       NaN 0.0000000 0.8513399 1.0000000       NaN       NaN       NaN
+  [8] 1.0000000 0.0000000 0.0000000       NaN 1.0000000       NaN 0.0000000
+ [15] 0.0080000       NaN       NaN 0.0000000       NaN 1.0000000       NaN
+ [22] 0.0000000       NaN 1.0000000       NaN       NaN 1.0000000 1.0000000
+ [29]       NaN 0.0000000       NaN 1.0000000 0.0000000 0.0000000       NaN
+ [36]       NaN       NaN 0.0000000 0.2349238 1.0000000       NaN 0.0000000
+ [43]       NaN 1.0000000 0.0000000       NaN       NaN 1.0000000       NaN
+ [50] 0.0000000       NaN 1.0000000       NaN 0.0000000       NaN       NaN
+ [57] 0.0000000 0.0000000       NaN 1.0000000       NaN 0.0000000 0.8513399
+ [64] 1.0000000       NaN       NaN       NaN 1.0000000 0.0000000 0.0000000
+ [71]       NaN 1.0000000       NaN 0.0000000 0.0080000       NaN       NaN
+ [78] 0.0000000       NaN 1.0000000       NaN 0.0000000       NaN 1.0000000
+ [85]       NaN       NaN 1.0000000 1.0000000       NaN 0.0000000       NaN
+ [92] 1.0000000 0.0000000 0.0000000       NaN       NaN       NaN 0.0000000
+ [99] 0.2349238 1.0000000       NaN 0.0000000       NaN 1.0000000 0.0000000
+[106]       NaN       NaN 1.0000000       NaN 0.0000000       NaN 1.0000000
+[113]       NaN 0.0000000       NaN       NaN 0.0000000 0.0000000       NaN
+[120] 1.0000000
+Warning message:
+In pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=TRUE)
+  [1]        NaN       -Inf -0.1609438  0.0000000        NaN        NaN
+  [7]        NaN  0.0000000       -Inf       -Inf        NaN  0.0000000
+ [13]        NaN       -Inf -4.8283137        NaN        NaN       -Inf
+ [19]        NaN  0.0000000        NaN       -Inf        NaN  0.0000000
+ [25]        NaN        NaN  0.0000000  0.0000000        NaN       -Inf
+ [31]        NaN  0.0000000       -Inf       -Inf        NaN        NaN
+ [37]        NaN       -Inf -1.4484941  0.0000000        NaN       -Inf
+ [43]        NaN  0.0000000       -Inf        NaN        NaN  0.0000000
+ [49]        NaN       -Inf        NaN  0.0000000        NaN       -Inf
+ [55]        NaN        NaN       -Inf       -Inf        NaN  0.0000000
+ [61]        NaN       -Inf -0.1609438  0.0000000        NaN        NaN
+ [67]        NaN  0.0000000       -Inf       -Inf        NaN  0.0000000
+ [73]        NaN       -Inf -4.8283137        NaN        NaN       -Inf
+ [79]        NaN  0.0000000        NaN       -Inf        NaN  0.0000000
+ [85]        NaN        NaN  0.0000000  0.0000000        NaN       -Inf
+ [91]        NaN  0.0000000       -Inf       -Inf        NaN        NaN
+ [97]        NaN       -Inf -1.4484941  0.0000000        NaN       -Inf
+[103]        NaN  0.0000000       -Inf        NaN        NaN  0.0000000
+[109]        NaN       -Inf        NaN  0.0000000        NaN       -Inf
+[115]        NaN        NaN       -Inf       -Inf        NaN  0.0000000
+Warning message:
+In pbeta(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); pbeta(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5))
+ [1]  NA   0 NaN   1   0  NA   0 NaN   1   0  NA   0 NaN   1   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); pbeta(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]  NA   0 NaN   1 NaN  NA   1 NaN   0 NaN  NA   1 NaN   0 NaN
+Warning message:
+In pbeta(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pbeta(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]  NA   0 NaN   1 NaN  NA   1 NaN   1 NaN  NA   0 NaN   0 NaN
+Warning message:
+In pbeta(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, 10, 10, lower.tail=FALSE, log.p=FALSE)
+[1] 0.75
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, 10, 10, lower.tail=FALSE, log.p=TRUE)
+[1] -0.2876821
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, 10, 10, lower.tail=TRUE, log.p=FALSE)
+[1] 0.25
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, 10, 10, lower.tail=TRUE, log.p=TRUE)
+[1] -1.386294
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=FALSE)
+ [1] 7.500000e-01 7.500000e-01 7.500000e-01 7.500000e-01 7.500000e-01
+ [6] 5.000000e-01 3.915212e-05 1.000000e+00 5.000000e-01 5.000000e-01
+[11] 9.999976e-01 1.000000e+00 5.000000e-01 4.999640e-01 5.000000e-01
+[16] 5.005996e-01 5.000000e-01 1.000000e+00 1.000000e+00 5.000000e-01
+[21] 2.075617e-02 9.994004e-01 1.000000e+00 5.000000e-01 5.000000e-01
+[26] 1.000000e+00 5.000000e-01 1.018592e-79 5.000024e-01 5.000000e-01
+[31] 5.000000e-01 1.000000e+00 1.000000e+00 5.000000e-01 5.000000e-01
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=TRUE)
+ [1]  -2.876821e-01  -2.876821e-01  -2.876821e-01  -2.876821e-01  -2.876821e-01
+ [6]  -6.931472e-01  -1.014806e+01  -1.559865e-78  -6.931472e-01  -6.931472e-01
+[11]  -2.353182e-06  -4.955964e-77  -6.931472e-01  -6.932193e-01  -6.931472e-01
+[16]  -6.919488e-01  -6.931472e-01  -1.153166e-83  -3.559027e-69  -6.931472e-01
+[21]  -3.874912e+00  -5.997521e-04  -8.281233e-76  -6.931472e-01  -6.931472e-01
+[26]  -2.631093e-74  -6.931472e-01  -1.818858e+02  -6.931425e-01  -6.931472e-01
+[31]  -6.931472e-01  -4.432482e-09 -1.289357e-151  -6.931472e-01  -6.931472e-01
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=FALSE)
+ [1]  2.500000e-01  2.500000e-01  2.500000e-01  2.500000e-01  2.500000e-01
+ [6]  5.000000e-01  9.999608e-01  1.559865e-78  5.000000e-01  5.000000e-01
+[11]  2.353180e-06  4.955964e-77  5.000000e-01  5.000360e-01  5.000000e-01
+[16]  4.994004e-01  5.000000e-01  1.153166e-83  3.559027e-69  5.000000e-01
+[21]  9.792438e-01  5.995723e-04  8.281233e-76  5.000000e-01  5.000000e-01
+[26]  2.631093e-74  5.000000e-01  1.000000e+00  4.999976e-01  5.000000e-01
+[31]  5.000000e-01  4.432482e-09 1.289357e-151  5.000000e-01  5.000000e-01
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=TRUE)
+ [1] -1.386294e+00 -1.386294e+00 -1.386294e+00 -1.386294e+00 -1.386294e+00
+ [6] -6.931472e-01 -3.915288e-05 -1.791570e+02 -6.931472e-01 -6.931472e-01
+[11] -1.295974e+01 -1.756985e+02 -6.931472e-01 -6.930751e-01 -6.931472e-01
+[16] -6.943470e-01 -6.931472e-01 -1.909721e+02 -1.576089e+02 -6.931472e-01
+[21] -2.097460e-02 -7.419294e+00 -1.728825e+02 -6.931472e-01 -6.931472e-01
+[26] -1.694239e+02 -6.931472e-01 -1.018592e-79 -6.931519e-01 -6.931472e-01
+[31] -6.931472e-01 -1.923431e+01 -3.474362e+02 -6.931472e-01 -6.931472e-01
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=FALSE)
+  [1]          NaN          NaN 4.682745e-01 2.885794e-02          NaN
+  [6] 3.183099e-05          NaN          NaN 8.457859e-01 9.893936e-01
+ [11]          NaN 1.591549e-05          NaN          NaN 8.908121e-01
+ [16] 1.060640e-02          NaN 9.996817e-01          NaN          NaN
+ [21] 5.000000e-01 5.000000e-01          NaN 2.893726e-05          NaN
+ [26]          NaN 4.371670e-01 1.673771e-02          NaN 9.999894e-01
+ [31]          NaN          NaN 7.651462e-01 9.647767e-01          NaN
+ [36] 1.061033e-05          NaN          NaN 6.944001e-01 9.682745e-01
+ [41]          NaN 5.000000e-01          NaN          NaN 9.220209e-01
+ [46] 3.172552e-02          NaN 1.675315e-05          NaN          NaN
+ [51] 2.211421e-01 1.590225e-02          NaN 9.999646e-01          NaN
+ [56]          NaN 7.500000e-01 7.500000e-01          NaN 9.999682e-01
+ [61]          NaN          NaN 4.682745e-01 2.885794e-02          NaN
+ [66] 3.183099e-05          NaN          NaN 8.457859e-01 9.893936e-01
+ [71]          NaN 1.591549e-05          NaN          NaN 8.908121e-01
+ [76] 1.060640e-02          NaN 9.996817e-01          NaN          NaN
+ [81] 5.000000e-01 5.000000e-01          NaN 2.893726e-05          NaN
+ [86]          NaN 4.371670e-01 1.673771e-02          NaN 9.999894e-01
+ [91]          NaN          NaN 7.651462e-01 9.647767e-01          NaN
+ [96] 1.061033e-05          NaN          NaN 6.944001e-01 9.682745e-01
+[101]          NaN 5.000000e-01          NaN          NaN 9.220209e-01
+[106] 3.172552e-02          NaN 1.675315e-05          NaN          NaN
+[111] 2.211421e-01 1.590225e-02          NaN 9.999646e-01          NaN
+[116]          NaN 7.500000e-01 7.500000e-01          NaN 9.999682e-01
+Warning message:
+In pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=TRUE)
+  [1]           NaN           NaN -7.587007e-01 -3.545370e+00           NaN
+  [6] -1.035507e+01           NaN           NaN -1.674890e-01 -1.066305e-02
+ [11]           NaN -1.104822e+01           NaN           NaN -1.156218e-01
+ [16] -4.546297e+00           NaN -3.183605e-04           NaN           NaN
+ [21] -6.931472e-01 -6.931472e-01           NaN -1.045038e+01           NaN
+ [26]           NaN -8.274399e-01 -4.090091e+00           NaN -1.061039e-05
+ [31]           NaN           NaN -2.676884e-01 -3.585859e-02           NaN
+ [36] -1.145368e+01           NaN           NaN -3.647070e-01 -3.223968e-02
+ [41]           NaN -6.931472e-01           NaN           NaN -8.118742e-02
+ [46] -3.450634e+00           NaN -1.099692e+01           NaN           NaN
+ [51] -1.508950e+00 -4.141295e+00           NaN -3.536839e-05           NaN
+ [56]           NaN -2.876821e-01 -2.876821e-01           NaN -3.183150e-05
+ [61]           NaN           NaN -7.587007e-01 -3.545370e+00           NaN
+ [66] -1.035507e+01           NaN           NaN -1.674890e-01 -1.066305e-02
+ [71]           NaN -1.104822e+01           NaN           NaN -1.156218e-01
+ [76] -4.546297e+00           NaN -3.183605e-04           NaN           NaN
+ [81] -6.931472e-01 -6.931472e-01           NaN -1.045038e+01           NaN
+ [86]           NaN -8.274399e-01 -4.090091e+00           NaN -1.061039e-05
+ [91]           NaN           NaN -2.676884e-01 -3.585859e-02           NaN
+ [96] -1.145368e+01           NaN           NaN -3.647070e-01 -3.223968e-02
+[101]           NaN -6.931472e-01           NaN           NaN -8.118742e-02
+[106] -3.450634e+00           NaN -1.099692e+01           NaN           NaN
+[111] -1.508950e+00 -4.141295e+00           NaN -3.536839e-05           NaN
+[116]           NaN -2.876821e-01 -2.876821e-01           NaN -3.183150e-05
+Warning message:
+In pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=FALSE)
+  [1]          NaN          NaN 5.317255e-01 9.711421e-01          NaN
+  [6] 9.999682e-01          NaN          NaN 1.542141e-01 1.060640e-02
+ [11]          NaN 9.999841e-01          NaN          NaN 1.091879e-01
+ [16] 9.893936e-01          NaN 3.183098e-04          NaN          NaN
+ [21] 5.000000e-01 5.000000e-01          NaN 9.999711e-01          NaN
+ [26]          NaN 5.628330e-01 9.832623e-01          NaN 1.061033e-05
+ [31]          NaN          NaN 2.348538e-01 3.522329e-02          NaN
+ [36] 9.999894e-01          NaN          NaN 3.055999e-01 3.172552e-02
+ [41]          NaN 5.000000e-01          NaN          NaN 7.797913e-02
+ [46] 9.682745e-01          NaN 9.999832e-01          NaN          NaN
+ [51] 7.788579e-01 9.840977e-01          NaN 3.536776e-05          NaN
+ [56]          NaN 2.500000e-01 2.500000e-01          NaN 3.183099e-05
+ [61]          NaN          NaN 5.317255e-01 9.711421e-01          NaN
+ [66] 9.999682e-01          NaN          NaN 1.542141e-01 1.060640e-02
+ [71]          NaN 9.999841e-01          NaN          NaN 1.091879e-01
+ [76] 9.893936e-01          NaN 3.183098e-04          NaN          NaN
+ [81] 5.000000e-01 5.000000e-01          NaN 9.999711e-01          NaN
+ [86]          NaN 5.628330e-01 9.832623e-01          NaN 1.061033e-05
+ [91]          NaN          NaN 2.348538e-01 3.522329e-02          NaN
+ [96] 9.999894e-01          NaN          NaN 3.055999e-01 3.172552e-02
+[101]          NaN 5.000000e-01          NaN          NaN 7.797913e-02
+[106] 9.682745e-01          NaN 9.999832e-01          NaN          NaN
+[111] 7.788579e-01 9.840977e-01          NaN 3.536776e-05          NaN
+[116]          NaN 2.500000e-01 2.500000e-01          NaN 3.183099e-05
+Warning message:
+In pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=TRUE)
+  [1]           NaN           NaN -6.316279e-01 -2.928252e-02           NaN
+  [6] -3.183150e-05           NaN           NaN -1.869413e+00 -4.546297e+00
+ [11]           NaN -1.591562e-05           NaN           NaN -2.214685e+00
+ [16] -1.066305e-02           NaN -8.052485e+00           NaN           NaN
+ [21] -6.931472e-01 -6.931472e-01           NaN -2.893768e-05           NaN
+ [26]           NaN -5.747724e-01 -1.687937e-02           NaN -1.145368e+01
+ [31]           NaN           NaN -1.448792e+00 -3.346048e+00           NaN
+ [36] -1.061039e-05           NaN           NaN -1.185479e+00 -3.450634e+00
+ [41]           NaN -6.931472e-01           NaN           NaN -2.551314e+00
+ [46] -3.223968e-02           NaN -1.675329e-05           NaN           NaN
+ [51] -2.499266e-01 -1.603005e-02           NaN -1.024971e+01           NaN
+ [56]           NaN -1.386294e+00 -1.386294e+00           NaN -1.035507e+01
+ [61]           NaN           NaN -6.316279e-01 -2.928252e-02           NaN
+ [66] -3.183150e-05           NaN           NaN -1.869413e+00 -4.546297e+00
+ [71]           NaN -1.591562e-05           NaN           NaN -2.214685e+00
+ [76] -1.066305e-02           NaN -8.052485e+00           NaN           NaN
+ [81] -6.931472e-01 -6.931472e-01           NaN -2.893768e-05           NaN
+ [86]           NaN -5.747724e-01 -1.687937e-02           NaN -1.145368e+01
+ [91]           NaN           NaN -1.448792e+00 -3.346048e+00           NaN
+ [96] -1.061039e-05           NaN           NaN -1.185479e+00 -3.450634e+00
+[101]           NaN -6.931472e-01           NaN           NaN -2.551314e+00
+[106] -3.223968e-02           NaN -1.675329e-05           NaN           NaN
+[111] -2.499266e-01 -1.603005e-02           NaN -1.024971e+01           NaN
+[116]           NaN -1.386294e+00 -1.386294e+00           NaN -1.035507e+01
+Warning message:
+In pcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); pcauchy(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5))
+ [1]   NA  NaN  NaN 1.00  NaN   NA 0.25  NaN 1.00 0.00   NA 0.25  NaN  NaN 0.00
+Warning message:
+In pcauchy(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); pcauchy(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]   NA  NaN  NaN 0.00  NaN   NA 0.75  NaN 0.00 1.00   NA 0.75  NaN  NaN 1.00
+Warning message:
+In pcauchy(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); pcauchy(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]  NA NaN NaN 0.5 NaN  NA NaN NaN 0.5 NaN  NA NaN NaN 0.5 NaN
+Warning message:
+In pcauchy(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, 10, 10, lower.tail=FALSE, log.p=FALSE)
+[1] 1
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, 10, 10, lower.tail=FALSE, log.p=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, 10, 10, lower.tail=TRUE, log.p=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, 10, 10, lower.tail=TRUE, log.p=TRUE)
+[1] -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=FALSE)
+ [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=TRUE)
+ [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=FALSE)
+ [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=TRUE)
+ [1] -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf
+[16] -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf
+[31] -Inf -Inf -Inf -Inf -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=FALSE)
+  [1]          NaN 1.000000e+00 9.563151e-01 9.807048e-01          NaN
+  [6] 1.000000e+00          NaN 0.000000e+00 1.000000e+00 1.000000e+00
+ [11]          NaN 0.000000e+00          NaN 1.000000e+00 9.999980e-01
+ [16] 1.318515e-64          NaN 1.000000e+00          NaN 1.000000e+00
+ [21] 1.000000e+00 1.000000e+00          NaN 1.000000e+00          NaN
+ [26] 1.000000e+00 9.462397e-01 1.501156e-09          NaN 1.000000e+00
+ [31]          NaN 0.000000e+00 1.000000e+00 1.000000e+00          NaN
+ [36] 0.000000e+00          NaN 1.000000e+00 9.939538e-01 1.000000e+00
+ [41]          NaN 1.000000e+00          NaN 1.000000e+00 1.000000e+00
+ [46] 1.000000e+00          NaN 0.000000e+00          NaN 1.000000e+00
+ [51] 7.288829e-01 2.082422e-12          NaN 1.000000e+00          NaN
+ [56] 0.000000e+00 1.000000e+00 1.000000e+00          NaN 1.000000e+00
+ [61]          NaN 1.000000e+00 9.563151e-01 9.807048e-01          NaN
+ [66] 1.000000e+00          NaN 0.000000e+00 1.000000e+00 1.000000e+00
+ [71]          NaN 0.000000e+00          NaN 1.000000e+00 9.999980e-01
+ [76] 1.318515e-64          NaN 1.000000e+00          NaN 1.000000e+00
+ [81] 1.000000e+00 1.000000e+00          NaN 1.000000e+00          NaN
+ [86] 1.000000e+00 9.462397e-01 1.501156e-09          NaN 1.000000e+00
+ [91]          NaN 0.000000e+00 1.000000e+00 1.000000e+00          NaN
+ [96] 0.000000e+00          NaN 1.000000e+00 9.939538e-01 1.000000e+00
+[101]          NaN 1.000000e+00          NaN 1.000000e+00 1.000000e+00
+[106] 1.000000e+00          NaN 0.000000e+00          NaN 1.000000e+00
+[111] 7.288829e-01 2.082422e-12          NaN 1.000000e+00          NaN
+[116] 0.000000e+00 1.000000e+00 1.000000e+00          NaN 1.000000e+00
+Warning message:
+In plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=TRUE)
+  [1]            NaN   0.000000e+00  -4.466785e-02  -1.948377e-02            NaN
+  [6]   0.000000e+00            NaN           -Inf   0.000000e+00   0.000000e+00
+ [11]            NaN  -2.402266e+07            NaN   0.000000e+00  -2.018797e-06
+ [16]  -1.470889e+02            NaN   0.000000e+00            NaN   0.000000e+00
+ [21]   0.000000e+00   0.000000e+00            NaN   0.000000e+00            NaN
+ [26]   0.000000e+00  -5.525937e-02  -2.031703e+01            NaN   0.000000e+00
+ [31]            NaN           -Inf   0.000000e+00   0.000000e+00            NaN
+ [36]  -1.433374e+08            NaN   0.000000e+00  -6.064526e-03 -4.793526e-118
+ [41]            NaN   0.000000e+00            NaN   0.000000e+00   0.000000e+00
+ [46]   0.000000e+00            NaN  -1.759119e+07            NaN   0.000000e+00
+ [51]  -3.162422e-01  -2.689749e+01            NaN   0.000000e+00            NaN
+ [56]           -Inf   0.000000e+00   0.000000e+00            NaN   0.000000e+00
+ [61]            NaN   0.000000e+00  -4.466785e-02  -1.948377e-02            NaN
+ [66]   0.000000e+00            NaN           -Inf   0.000000e+00   0.000000e+00
+ [71]            NaN  -2.402266e+07            NaN   0.000000e+00  -2.018797e-06
+ [76]  -1.470889e+02            NaN   0.000000e+00            NaN   0.000000e+00
+ [81]   0.000000e+00   0.000000e+00            NaN   0.000000e+00            NaN
+ [86]   0.000000e+00  -5.525937e-02  -2.031703e+01            NaN   0.000000e+00
+ [91]            NaN           -Inf   0.000000e+00   0.000000e+00            NaN
+ [96]  -1.433374e+08            NaN   0.000000e+00  -6.064526e-03 -4.793526e-118
+[101]            NaN   0.000000e+00            NaN   0.000000e+00   0.000000e+00
+[106]   0.000000e+00            NaN  -1.759119e+07            NaN   0.000000e+00
+[111]  -3.162422e-01  -2.689749e+01            NaN   0.000000e+00            NaN
+[116]           -Inf   0.000000e+00   0.000000e+00            NaN   0.000000e+00
+Warning message:
+In plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=FALSE)
+  [1]           NaN  0.000000e+00  4.368493e-02  1.929519e-02           NaN
+  [6]  0.000000e+00           NaN  1.000000e+00  0.000000e+00  0.000000e+00
+ [11]           NaN  1.000000e+00           NaN  0.000000e+00  2.018795e-06
+ [16]  1.000000e+00           NaN  0.000000e+00           NaN  0.000000e+00
+ [21]  0.000000e+00  0.000000e+00           NaN  0.000000e+00           NaN
+ [26]  0.000000e+00  5.376031e-02  1.000000e+00           NaN  0.000000e+00
+ [31]           NaN  1.000000e+00  0.000000e+00  0.000000e+00           NaN
+ [36]  1.000000e+00           NaN  0.000000e+00  6.046174e-03 4.793526e-118
+ [41]           NaN  0.000000e+00           NaN  0.000000e+00  0.000000e+00
+ [46]  0.000000e+00           NaN  1.000000e+00           NaN  0.000000e+00
+ [51]  2.711171e-01  1.000000e+00           NaN  0.000000e+00           NaN
+ [56]  1.000000e+00  0.000000e+00  0.000000e+00           NaN  0.000000e+00
+ [61]           NaN  0.000000e+00  4.368493e-02  1.929519e-02           NaN
+ [66]  0.000000e+00           NaN  1.000000e+00  0.000000e+00  0.000000e+00
+ [71]           NaN  1.000000e+00           NaN  0.000000e+00  2.018795e-06
+ [76]  1.000000e+00           NaN  0.000000e+00           NaN  0.000000e+00
+ [81]  0.000000e+00  0.000000e+00           NaN  0.000000e+00           NaN
+ [86]  0.000000e+00  5.376031e-02  1.000000e+00           NaN  0.000000e+00
+ [91]           NaN  1.000000e+00  0.000000e+00  0.000000e+00           NaN
+ [96]  1.000000e+00           NaN  0.000000e+00  6.046174e-03 4.793526e-118
+[101]           NaN  0.000000e+00           NaN  0.000000e+00  0.000000e+00
+[106]  0.000000e+00           NaN  1.000000e+00           NaN  0.000000e+00
+[111]  2.711171e-01  1.000000e+00           NaN  0.000000e+00           NaN
+[116]  1.000000e+00  0.000000e+00  0.000000e+00           NaN  0.000000e+00
+Warning message:
+In plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=TRUE)
+  [1]           NaN          -Inf -3.130752e+00 -3.947899e+00           NaN
+  [6]          -Inf           NaN  0.000000e+00          -Inf          -Inf
+ [11]           NaN  0.000000e+00           NaN          -Inf -1.311301e+01
+ [16] -1.318515e-64           NaN          -Inf           NaN          -Inf
+ [21]          -Inf          -Inf           NaN -2.139413e+06           NaN
+ [26]          -Inf -2.923220e+00 -1.501156e-09           NaN          -Inf
+ [31]           NaN  0.000000e+00          -Inf          -Inf           NaN
+ [36]  0.000000e+00           NaN          -Inf -5.108330e+00 -2.701378e+02
+ [41]           NaN          -Inf           NaN          -Inf          -Inf
+ [46]          -Inf           NaN  0.000000e+00           NaN          -Inf
+ [51] -1.305204e+00 -2.082422e-12           NaN          -Inf           NaN
+ [56]  0.000000e+00          -Inf          -Inf           NaN -2.660785e+08
+ [61]           NaN          -Inf -3.130752e+00 -3.947899e+00           NaN
+ [66]          -Inf           NaN  0.000000e+00          -Inf          -Inf
+ [71]           NaN  0.000000e+00           NaN          -Inf -1.311301e+01
+ [76] -1.318515e-64           NaN          -Inf           NaN          -Inf
+ [81]          -Inf          -Inf           NaN -2.139413e+06           NaN
+ [86]          -Inf -2.923220e+00 -1.501156e-09           NaN          -Inf
+ [91]           NaN  0.000000e+00          -Inf          -Inf           NaN
+ [96]  0.000000e+00           NaN          -Inf -5.108330e+00 -2.701378e+02
+[101]           NaN          -Inf           NaN          -Inf          -Inf
+[106]          -Inf           NaN  0.000000e+00           NaN          -Inf
+[111] -1.305204e+00 -2.082422e-12           NaN          -Inf           NaN
+[116]  0.000000e+00          -Inf          -Inf           NaN -2.660785e+08
+Warning message:
+In plnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); plnorm(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5))
+ [1]  NA   0 NaN   1   0  NA   0 NaN   1   0  NA   0 NaN   1   0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); plnorm(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]            NA  0.000000e+00           NaN  0.000000e+00  0.000000e+00
+ [6]            NA  5.000000e-01           NaN  0.000000e+00  1.000000e+00
+[11]            NA 1.284176e-117           NaN  0.000000e+00  1.000000e+00
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); plnorm(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]  NA 0.0 NaN 0.5 NaN  NA 0.0 NaN 0.5 NaN  NA 0.0 NaN 0.0 NaN
+Warning message:
+In plnorm(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, 10, 10, lower.tail=FALSE, log.p=FALSE)
+[1] Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, 10, 10, lower.tail=FALSE, log.p=TRUE)
+[1] -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, 10, 10, lower.tail=TRUE, log.p=FALSE)
+[1] -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, 10, 10, lower.tail=TRUE, log.p=TRUE)
+[1] Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=FALSE)
+ [1] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+[20] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=TRUE)
+ [1] -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf
+[16] -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf
+[31] -Inf -Inf -Inf -Inf -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=FALSE)
+ [1] -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf
+[16] -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf
+[31] -Inf -Inf -Inf -Inf -Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=TRUE)
+ [1] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+[20] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=FALSE)
+  [1]        NaN  0.0000000  1.4763819        NaN        NaN        Inf
+  [7]        NaN        NaN        NaN        Inf        NaN        NaN
+ [13]        NaN  0.9000000  4.3763819        NaN        NaN        Inf
+ [19]        NaN        NaN        NaN        Inf        NaN        NaN
+ [25]        NaN -1.0000000  1.3763819        NaN        NaN        Inf
+ [31]        NaN        NaN        NaN        Inf        NaN        NaN
+ [37]        NaN  0.1000000  2.2763819        NaN        NaN        Inf
+ [43]        NaN        NaN        NaN        Inf        NaN        NaN
+ [49]        NaN  3.0000000  0.3763819        NaN        NaN        Inf
+ [55]        NaN        NaN        NaN        Inf        NaN        NaN
+ [61]        NaN  0.0000000  1.4763819        NaN        NaN        Inf
+ [67]        NaN        NaN        NaN        Inf        NaN        NaN
+ [73]        NaN  0.9000000  4.3763819        NaN        NaN        Inf
+ [79]        NaN        NaN        NaN        Inf        NaN        NaN
+ [85]        NaN -1.0000000  1.3763819        NaN        NaN        Inf
+ [91]        NaN        NaN        NaN        Inf        NaN        NaN
+ [97]        NaN  0.1000000  2.2763819        NaN        NaN        Inf
+[103]        NaN        NaN        NaN        Inf        NaN        NaN
+[109]        NaN  3.0000000  0.3763819        NaN        NaN        Inf
+[115]        NaN        NaN        NaN        Inf        NaN        NaN
+Warning message:
+In qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=TRUE)
+  [1]        NaN  0.0000000        NaN        NaN        NaN       -Inf
+  [7]        NaN        NaN  1.3406711       -Inf        NaN        NaN
+ [13]        NaN  0.9000000        NaN        NaN        NaN       -Inf
+ [19]        NaN        NaN -0.5593289       -Inf        NaN        NaN
+ [25]        NaN -1.0000000        NaN        NaN        NaN       -Inf
+ [31]        NaN        NaN  0.5406711       -Inf        NaN        NaN
+ [37]        NaN  0.1000000        NaN        NaN        NaN       -Inf
+ [43]        NaN        NaN  3.4406711       -Inf        NaN        NaN
+ [49]        NaN  3.0000000        NaN        NaN        NaN       -Inf
+ [55]        NaN        NaN  0.4406711       -Inf        NaN        NaN
+ [61]        NaN  0.0000000        NaN        NaN        NaN       -Inf
+ [67]        NaN        NaN  1.3406711       -Inf        NaN        NaN
+ [73]        NaN  0.9000000        NaN        NaN        NaN       -Inf
+ [79]        NaN        NaN -0.5593289       -Inf        NaN        NaN
+ [85]        NaN -1.0000000        NaN        NaN        NaN       -Inf
+ [91]        NaN        NaN  0.5406711       -Inf        NaN        NaN
+ [97]        NaN  0.1000000        NaN        NaN        NaN       -Inf
+[103]        NaN        NaN  3.4406711       -Inf        NaN        NaN
+[109]        NaN  3.0000000        NaN        NaN        NaN       -Inf
+[115]        NaN        NaN  0.4406711       -Inf        NaN        NaN
+Warning message:
+In qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=FALSE)
+  [1]        NaN  0.0000000 -1.2763819        NaN        NaN       -Inf
+  [7]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [13]        NaN  0.9000000  1.6236181        NaN        NaN       -Inf
+ [19]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [25]        NaN -1.0000000 -1.3763819        NaN        NaN       -Inf
+ [31]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [37]        NaN  0.1000000 -0.4763819        NaN        NaN       -Inf
+ [43]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [49]        NaN  3.0000000 -2.3763819        NaN        NaN       -Inf
+ [55]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [61]        NaN  0.0000000 -1.2763819        NaN        NaN       -Inf
+ [67]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [73]        NaN  0.9000000  1.6236181        NaN        NaN       -Inf
+ [79]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [85]        NaN -1.0000000 -1.3763819        NaN        NaN       -Inf
+ [91]        NaN        NaN        NaN       -Inf        NaN        NaN
+ [97]        NaN  0.1000000 -0.4763819        NaN        NaN       -Inf
+[103]        NaN        NaN        NaN       -Inf        NaN        NaN
+[109]        NaN  3.0000000 -2.3763819        NaN        NaN       -Inf
+[115]        NaN        NaN        NaN       -Inf        NaN        NaN
+Warning message:
+In qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=TRUE)
+  [1]        NaN  0.0000000        NaN        NaN        NaN        Inf
+  [7]        NaN        NaN  0.4593289        Inf        NaN        NaN
+ [13]        NaN  0.9000000        NaN        NaN        NaN        Inf
+ [19]        NaN        NaN -1.4406711        Inf        NaN        NaN
+ [25]        NaN -1.0000000        NaN        NaN        NaN        Inf
+ [31]        NaN        NaN -0.3406711        Inf        NaN        NaN
+ [37]        NaN  0.1000000        NaN        NaN        NaN        Inf
+ [43]        NaN        NaN  2.5593289        Inf        NaN        NaN
+ [49]        NaN  3.0000000        NaN        NaN        NaN        Inf
+ [55]        NaN        NaN -0.4406711        Inf        NaN        NaN
+ [61]        NaN  0.0000000        NaN        NaN        NaN        Inf
+ [67]        NaN        NaN  0.4593289        Inf        NaN        NaN
+ [73]        NaN  0.9000000        NaN        NaN        NaN        Inf
+ [79]        NaN        NaN -1.4406711        Inf        NaN        NaN
+ [85]        NaN -1.0000000        NaN        NaN        NaN        Inf
+ [91]        NaN        NaN -0.3406711        Inf        NaN        NaN
+ [97]        NaN  0.1000000        NaN        NaN        NaN        Inf
+[103]        NaN        NaN  2.5593289        Inf        NaN        NaN
+[109]        NaN  3.0000000        NaN        NaN        NaN        Inf
+[115]        NaN        NaN -0.4406711        Inf        NaN        NaN
+Warning message:
+In qcauchy(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); qcauchy(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5))
+ [1]   NA    0  NaN  NaN  NaN   NA -Inf  NaN  NaN  NaN   NA -Inf  NaN  NaN  NaN
+Warning message:
+In qcauchy(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); qcauchy(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]         NA  0.0000000        NaN        Inf       -Inf         NA
+ [7]        Inf        NaN        Inf        NaN         NA -0.3077684
+[13]        NaN        Inf       -Inf
+Warning message:
+In qcauchy(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qcauchy(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]  NA 0.0 NaN NaN NaN  NA 1.0 NaN NaN NaN  NA 0.1 NaN NaN NaN
+Warning message:
+In qcauchy(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, 10, 10, lower.tail=FALSE, log.p=FALSE)
+[1] Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, 10, 10, lower.tail=FALSE, log.p=TRUE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, 10, 10, lower.tail=TRUE, log.p=FALSE)
+[1] 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, 10, 10, lower.tail=TRUE, log.p=TRUE)
+[1] Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=FALSE)
+ [1] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+[20] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=FALSE, log.p=TRUE)
+ [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=FALSE)
+ [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7), lower.tail=TRUE, log.p=TRUE)
+ [1] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+[20] Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf Inf
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=FALSE)
+  [1]        NaN        Inf  2.5641351        NaN        NaN        Inf
+  [7]        NaN        NaN        NaN        Inf        NaN        NaN
+ [13]        NaN        Inf 46.6009643        NaN        NaN        Inf
+ [19]        NaN        NaN        NaN        Inf        NaN        NaN
+ [25]        NaN        Inf  2.3201254        NaN        NaN        Inf
+ [31]        NaN        NaN        NaN        Inf        NaN        NaN
+ [37]        NaN        Inf  5.7065876        NaN        NaN        Inf
+ [43]        NaN        NaN        NaN        Inf        NaN        NaN
+ [49]        NaN        Inf  0.8535264        NaN        NaN        Inf
+ [55]        NaN        NaN        NaN        Inf        NaN        NaN
+ [61]        NaN        Inf  2.5641351        NaN        NaN        Inf
+ [67]        NaN        NaN        NaN        Inf        NaN        NaN
+ [73]        NaN        Inf 46.6009643        NaN        NaN        Inf
+ [79]        NaN        NaN        NaN        Inf        NaN        NaN
+ [85]        NaN        Inf  2.3201254        NaN        NaN        Inf
+ [91]        NaN        NaN        NaN        Inf        NaN        NaN
+ [97]        NaN        Inf  5.7065876        NaN        NaN        Inf
+[103]        NaN        NaN        NaN        Inf        NaN        NaN
+[109]        NaN        Inf  0.8535264        NaN        NaN        Inf
+[115]        NaN        NaN        NaN        Inf        NaN        NaN
+Warning message:
+In qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=FALSE, log.p=TRUE)
+  [1]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+  [7]        NaN        NaN  3.4468989  0.0000000        NaN        NaN
+ [13]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+ [19]        NaN        NaN  0.5155479  0.0000000        NaN        NaN
+ [25]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+ [31]        NaN        NaN  1.5487915  0.0000000        NaN        NaN
+ [37]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+ [43]        NaN        NaN 28.1479623  0.0000000        NaN        NaN
+ [49]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+ [55]        NaN        NaN  1.4014045  0.0000000        NaN        NaN
+ [61]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+ [67]        NaN        NaN  3.4468989  0.0000000        NaN        NaN
+ [73]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+ [79]        NaN        NaN  0.5155479  0.0000000        NaN        NaN
+ [85]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+ [91]        NaN        NaN  1.5487915  0.0000000        NaN        NaN
+ [97]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+[103]        NaN        NaN 28.1479623  0.0000000        NaN        NaN
+[109]        NaN  0.0000000        NaN        NaN        NaN  0.0000000
+[115]        NaN        NaN  1.4014045  0.0000000        NaN        NaN
+Warning message:
+In qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=FALSE)
+  [1]       NaN 0.0000000 0.4763410       NaN       NaN 0.0000000       NaN
+  [8]       NaN       NaN 0.0000000       NaN       NaN       NaN 0.0000000
+ [15] 8.6570911       NaN       NaN 0.0000000       NaN       NaN       NaN
+ [22] 0.0000000       NaN       NaN       NaN 0.0000000 0.4310112       NaN
+ [29]       NaN 0.0000000       NaN       NaN       NaN 0.0000000       NaN
+ [36]       NaN       NaN 0.0000000 1.0601165       NaN       NaN 0.0000000
+ [43]       NaN       NaN       NaN 0.0000000       NaN       NaN       NaN
+ [50] 0.0000000 0.1585602       NaN       NaN 0.0000000       NaN       NaN
+ [57]       NaN 0.0000000       NaN       NaN       NaN 0.0000000 0.4763410
+ [64]       NaN       NaN 0.0000000       NaN       NaN       NaN 0.0000000
+ [71]       NaN       NaN       NaN 0.0000000 8.6570911       NaN       NaN
+ [78] 0.0000000       NaN       NaN       NaN 0.0000000       NaN       NaN
+ [85]       NaN 0.0000000 0.4310112       NaN       NaN 0.0000000       NaN
+ [92]       NaN       NaN 0.0000000       NaN       NaN       NaN 0.0000000
+ [99] 1.0601165       NaN       NaN 0.0000000       NaN       NaN       NaN
+[106] 0.0000000       NaN       NaN       NaN 0.0000000 0.1585602       NaN
+[113]       NaN 0.0000000       NaN       NaN       NaN 0.0000000       NaN
+[120]       NaN
+Warning message:
+In qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20), lower.tail=TRUE, log.p=TRUE)
+  [1]        NaN        Inf        NaN        NaN        NaN        Inf
+  [7]        NaN        NaN  1.7550986        Inf        NaN        NaN
+ [13]        NaN        Inf        NaN        NaN        NaN        Inf
+ [19]        NaN        NaN  0.2625077        Inf        NaN        NaN
+ [25]        NaN        Inf        NaN        NaN        NaN        Inf
+ [31]        NaN        NaN  0.7886166        Inf        NaN        NaN
+ [37]        NaN        Inf        NaN        NaN        NaN        Inf
+ [43]        NaN        NaN 14.3324334        Inf        NaN        NaN
+ [49]        NaN        Inf        NaN        NaN        NaN        Inf
+ [55]        NaN        NaN  0.7135698        Inf        NaN        NaN
+ [61]        NaN        Inf        NaN        NaN        NaN        Inf
+ [67]        NaN        NaN  1.7550986        Inf        NaN        NaN
+ [73]        NaN        Inf        NaN        NaN        NaN        Inf
+ [79]        NaN        NaN  0.2625077        Inf        NaN        NaN
+ [85]        NaN        Inf        NaN        NaN        NaN        Inf
+ [91]        NaN        NaN  0.7886166        Inf        NaN        NaN
+ [97]        NaN        Inf        NaN        NaN        NaN        Inf
+[103]        NaN        NaN 14.3324334        Inf        NaN        NaN
+[109]        NaN        Inf        NaN        NaN        NaN        Inf
+[115]        NaN        NaN  0.7135698        Inf        NaN        NaN
+Warning message:
+In qlnorm(c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); qlnorm(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5))
+ [1]  NA   0 NaN NaN NaN  NA   0 NaN NaN NaN  NA   0 NaN NaN NaN
+Warning message:
+In qlnorm(c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1,  :
+  NaNs produced
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWarningContext#
+#set.seed(1); qlnorm(rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5))
+ [1]        NA 0.0000000       NaN       Inf 0.0000000        NA       Inf
+ [8]       NaN       Inf       Inf        NA 0.8797169       NaN 0.0000000
+[15] 0.0000000
+
+##com.oracle.truffle.r.test.library.stats.TestStatFunctions.testFunctions32#Output.IgnoreWhitespace#
+#set.seed(1); qlnorm(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0))
+ [1]       NA 0.000000      NaN      Inf 0.000000       NA      Inf      NaN
+ [9] 0.000000      Inf       NA 1.105171      NaN 0.000000      NaN
+Warning message:
+In qlnorm(rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN,  :
+  NaNs produced
+
 ##com.oracle.truffle.r.test.library.stats.TestStats.testCor#
 #{ as.integer(cor(c(1,2,3),c(1,2,5))*10000000) }
 [1] 9607689
@@ -114564,6 +116561,34 @@ In qnorm(c(0.1, 0.9, 0.5, 1.00001, 0.99999), 100, c(20, 1)) : NaNs produced
 #{ set.seed(7); round( rbinom(3,3,0.9), digits = 5 ) }
 [1] 1 3 3
 
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( rcauchy(3), digits = 5 ) }
+[1] -0.03486  3.00509  0.38038
+
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( rcauchy(3, scale=4, location=1:3), digits = 5 ) }
+[1]  0.86057 14.02037  4.52150
+
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( rgamma(3,0.5,rate=1:3), digits = 5 ) }
+[1] 3.63965 0.00938 0.02776
+
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( rgamma(3,0.5,scale=1:3), digits = 5 ) }
+[1] 3.63965 0.03753 0.24984
+
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( rgamma(3,1), digits = 5 ) }
+[1] 3.42520 0.95263 2.76594
+
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( rlnorm(3), digits = 5 ) }
+[1] 9.84779 0.30217 0.49943
+
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( rlnorm(3,sdlog=c(10,3,0.5)), digits = 5 ) }
+[1] 8.578043e+09 2.759000e-02 7.067000e-01
+
 ##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
 #{ set.seed(7); round( rnorm(3,c(1000,2,3),c(10,11)), digits = 5 ) }
 [1] 1022.87247  -11.16449   -3.94293
@@ -114576,6 +116601,10 @@ In qnorm(c(0.1, 0.9, 0.5, 1.00001, 0.99999), 100, c(20, 1)) : NaNs produced
 #{ set.seed(7); round( runif(3,1,10), digits = 5 ) }
 [1] 9.90018 4.57971 2.04128
 
+##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
+#{ set.seed(7); round( runif(3,1:3,3:2), digits = 5 ) }
+[1] 2.97782 2.00000 3.00000
+
 ##com.oracle.truffle.r.test.library.stats.TestStats.testRandom#
 #{ set.seed(7); runif(10) }
  [1] 0.98890930 0.39774545 0.11569778 0.06974868 0.24374939 0.79201043
@@ -114713,38 +116742,6 @@ In qnorm(c(0.1, 0.9, 0.5, 1.00001, 0.99999), 100, c(20, 1)) : NaNs produced
 #{ set.seed(9567, "Marsaglia-Multicarry"); sum(runif(100)) }
 [1] 52.92218
 
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( rcauchy(3), digits = 5 ) }
-[1] -0.03486  3.00509  0.38038
-
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( rcauchy(3, scale=4, location=1:3), digits = 5 ) }
-[1]  0.86057 14.02037  4.52150
-
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( rgamma(3,0.5,rate=1:3), digits = 5 ) }
-[1] 3.63965 0.00938 0.02776
-
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( rgamma(3,0.5,scale=1:3), digits = 5 ) }
-[1] 3.63965 0.03753 0.24984
-
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( rgamma(3,1), digits = 5 ) }
-[1] 3.42520 0.95263 2.76594
-
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( rlnorm(3), digits = 5 ) }
-[1] 9.84779 0.30217 0.49943
-
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( rlnorm(3,sdlog=c(10,3,0.5)), digits = 5 ) }
-[1] 8.578043e+09 2.759000e-02 7.067000e-01
-
-##com.oracle.truffle.r.test.library.stats.TestStats.testRandomIgnore#Ignored.Unknown#
-#{ set.seed(7); round( runif(3,1:3,3:2), digits = 5 ) }
-[1] 2.97782 2.00000 3.00000
-
 ##com.oracle.truffle.r.test.library.stats.TestStats.testRbinom#
 #set.seed(123); rbinom(1,20,c(0.3,0.2))
 [1] 5
@@ -115168,15 +117165,15 @@ Error: unexpected '*' in:
 [1] TRUE
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI1#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.addInt(2L, 3L); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.addInt(2L, 3L); detach("package:testrffi", unload=T); x }
 [1] 5
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI10#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); a <- c(1L,2L,3L); x <- rffi.iterate_iptr(a); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); a <- c(1L,2L,3L); x <- rffi.iterate_iptr(a); detach("package:testrffi", unload=T); x }
 [1] 1 2 3
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI11#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.dotCModifiedArguments(c(0,1,2,3)); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.dotCModifiedArguments(c(0,1,2,3)); detach("package:testrffi", unload=T); x }
 [[1]]
 [1] 4
 
@@ -115191,7 +117188,7 @@ Error: unexpected '*' in:
 
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI12#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.dotExternalAccessArgs(1L, 3, c(1,2,3), c('a', 'b'), 'b', TRUE, as.raw(12)); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.dotExternalAccessArgs(1L, 3, c(1,2,3), c('a', 'b'), 'b', TRUE, as.raw(12)); detach("package:testrffi", unload=T); x }
 [[1]]
 [[1]][[1]]
 NULL
@@ -115250,7 +117247,7 @@ NULL
 
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI13#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.dotExternalAccessArgs(x=1L, 3, c(1,2,3), y=c('a', 'b'), 'b', TRUE, as.raw(12)); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.dotExternalAccessArgs(x=1L, 3, c(1,2,3), y=c('a', 'b'), 'b', TRUE, as.raw(12)); detach("package:testrffi", unload=T); x }
 [[1]]
 [[1]][[1]]
 x
@@ -115309,59 +117306,68 @@ NULL
 
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI14#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.invoke12(); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.invoke12(); detach("package:testrffi", unload=T); x }
 [1] 12
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI15#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.TYPEOF(3L); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.TYPEOF(3L); detach("package:testrffi", unload=T); x }
 [1] 13
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI16#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.isRString("hello"); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.isRString("hello"); detach("package:testrffi", unload=T); x }
 [1] TRUE
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI17#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.isRString(NULL); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.isRString(NULL); detach("package:testrffi", unload=T); x }
 [1] FALSE
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI18#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.interactive(); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.interactive(); detach("package:testrffi", unload=T); x }
 [1] FALSE
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI19#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- 1; x <- rffi.findVar(x, globalenv()); detach("package:testrffi"); x }
-Error: could not find function "rffi.findVar"
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- 1; x <- rffi.findvar("x", globalenv()); detach("package:testrffi", unload=T); x }
+[1] 1
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI2#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.addDouble(2, 3); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.addDouble(2, 3); detach("package:testrffi", unload=T); x }
 [1] 5
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI3#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.populateIntVector(5); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.populateIntVector(5); detach("package:testrffi", unload=T); x }
 [1] 0 1 2 3 4
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI4#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.populateLogicalVector(5); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.populateLogicalVector(5); detach("package:testrffi", unload=T); x }
 [1]  TRUE    NA FALSE FALSE FALSE
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI5#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.mkStringFromChar(); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.mkStringFromChar(); detach("package:testrffi", unload=T); x }
 [1] "hello"
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI6#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.mkStringFromBytes(); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.mkStringFromBytes(); detach("package:testrffi", unload=T); x }
 [1] "hello"
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI7#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.null(); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.null(); detach("package:testrffi", unload=T); x }
 NULL
 
+##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI7C#
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.null.C(); detach("package:testrffi", unload=T); x }
+NULL
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI7E#
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.null.E(); detach("package:testrffi", unload=T); x }
+Error in .Call("null", PACKAGE = "foo") :
+  "null" not available for .Call() for package "foo"
+
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI8#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.isRString(character(0)); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- rffi.isRString(character(0)); detach("package:testrffi", unload=T); x }
 [1] TRUE
 
 ##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testRFFI9#
-#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); a <- c(1L,2L,3L); x <- rffi.iterate_iarray(a); detach("package:testrffi"); x }
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); a <- c(1L,2L,3L); x <- rffi.iterate_iarray(a); detach("package:testrffi", unload=T); x }
 [1] 1 2 3
 
 ##com.oracle.truffle.r.test.rffi.TestUserRNG.testUserRNG#
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java
index 41a29e7c30c60c0d76f902975ed2a4fa92aba4e6..30a6d6d91d5452eaf144a3e67ac8336438ae1ee9 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/S4/TestS4.java
@@ -85,7 +85,7 @@ public class TestS4 extends TestRBase {
     public void testAllocation() {
         assertEval("{ new(\"numeric\") }");
         assertEval("{ setClass(\"foo\", representation(j=\"numeric\")); new(\"foo\", j=42) }");
-
+        assertEval("{ setClass(\"foo\", representation(j=\"numeric\")); typeof(new(\"foo\", j=42)) }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java
index cea95545ce24d229ee5943fa53220345c2d9141b..4b36de5ed4b3ff0531c106d3a2e6413b7d2274db 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java
@@ -31,4 +31,15 @@ public class TestBuiltin_anyNA extends TestBase {
         assertEval("anyNA(list(list(4,5,NA), 3), recursive=TRUE)");
     }
 
+    @Test
+    public void testanyNA3() {
+        assertEval("anyNA(c(1, 2, 3))");
+        assertEval("anyNA(c(1, NA, 3))");
+        assertEval("anyNA(c(1, NA, 3), recursive = TRUE)");
+        assertEval("anyNA(list(a = c(1, 2, 3), b = 'a'))");
+        assertEval("anyNA(list(a = c(1, NA, 3), b = 'a'))");
+        assertEval("anyNA(list(a = c(1, 2, 3), b = 'a'), recursive = TRUE)");
+        assertEval("anyNA(list(a = c(1, NA, 3), b = 'a'), recursive = TRUE)");
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java
index 6deb046c20253c0a5cfe6b6d718e071506d28b21..41bcaeff061282aa915931433bb3373631865486 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascharacter.java
@@ -197,7 +197,7 @@ public class TestBuiltin_ascharacter extends TestBase {
 
     @Test
     public void testascharacter36() {
-        assertEval(Ignored.Unknown, "argv <- list(list(exit.code = 0L, send = NULL));as.character(argv[[1]]);");
+        assertEval("argv <- list(list(exit.code = 0L, send = NULL));as.character(argv[[1]]);");
     }
 
     @Test
@@ -262,7 +262,7 @@ public class TestBuiltin_ascharacter extends TestBase {
         assertEval("{ as.character(list(c(\"hello\", \"hi\"))) }");
         assertEval("{ as.character(list(list(c(\"hello\", \"hi\")))) }");
         assertEval("{ as.character(list(c(2L, 3L))) }");
-        assertEval(Ignored.Unknown, "{ as.character(list(c(2L, 3L, 5L))) }"); // GnuR prints no L
+        assertEval("{ as.character(list(c(2L, 3L, 5L))) }");
 
         assertEval("{ x<-as.character(Sys.time()) }");
         assertEval("{ f<-function(x) { sys.call() }; as.character(f(7)) }");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_det.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_det.java
index 03c916578780d4c15100169745c7226f424c5881..bc9640f6a04b95851c0127e2cc03d9de885e18ca 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_det.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_det.java
@@ -41,6 +41,6 @@ public class TestBuiltin_det extends TestBase {
     public void testDet() {
         assertEval("{ det(matrix(c(1,2,4,5),nrow=2)) }");
         assertEval("{ det(matrix(c(1,-3,4,-5),nrow=2)) }");
-        assertEval(Ignored.Unknown, "{ det(matrix(c(1,0,4,NA),nrow=2)) }");
+        assertEval("{ det(matrix(c(1,0,4,NA),nrow=2)) }");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimassign.java
index da6bda1e0cb7cc2ebe39516bfc246518da3e8a63..f76298ead2b14bf7a33e0e1fee0011b14932c8af 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimassign.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_dimassign.java
@@ -71,4 +71,10 @@ public class TestBuiltin_dimassign extends TestBase {
     public void testdimassign11() {
         assertEval("argv <- list(structure(NA, .Dim = c(1L, 1L)), value = c(1L, 1L));`dim<-`(argv[[1]],argv[[2]]);");
     }
+
+    @Test
+    public void testdimassign12() {
+        assertEval("b <- c(a=1+2i,b=3+4i);dim(b) <- c(2,1);attributes(x)");
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
index 6811de383289d6f4fd895805930c125ee5e77f33..d2fdc75685a637c5ee7d4bb80484fef5a580ecc2 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java
@@ -114,7 +114,7 @@ public class TestBuiltin_identical extends TestBase {
 
     @Test
     public void testidentical20() {
-        assertEval(Ignored.Unknown, "argv <- list(NaN, NaN, TRUE, TRUE, TRUE, TRUE, FALSE); .Internal(identical(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
+        assertEval("argv <- list(NaN, NaN, TRUE, TRUE, TRUE, TRUE, FALSE); .Internal(identical(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
     }
 
     @Test
@@ -196,9 +196,8 @@ public class TestBuiltin_identical extends TestBase {
 
     @Test
     public void testidentical37() {
-        assertEval(Ignored.Unknown,
-                        "argv <- structure(list(x = structure(list(a = NA, b = NA_integer_,     c = NA_real_, d = NA_complex_, e = 1, f = 1L, g = 1:3, h = c(NA,         1L, 2L, 3L), i = NA_character_, j = c('foo', NA, 'bar')),     .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')),     y = structure(list(a = NA, b = NA_integer_, c = NA_real_,         d = NA_complex_, e = 1, f = 1L, g = 1:3, h = c(NA, 1L,             2L, 3L), i = NA_character_, j = c('foo', NA, 'bar')),         .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',             'j'))), .Names = c('x', 'y'));" +
-                                        "do.call('identical', argv)");
+        assertEval("argv <- structure(list(x = structure(list(a = NA, b = NA_integer_,     c = NA_real_, d = NA_complex_, e = 1, f = 1L, g = 1:3, h = c(NA,         1L, 2L, 3L), i = NA_character_, j = c('foo', NA, 'bar')),     .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j')),     y = structure(list(a = NA, b = NA_integer_, c = NA_real_,         d = NA_complex_, e = 1, f = 1L, g = 1:3, h = c(NA, 1L,             2L, 3L), i = NA_character_, j = c('foo', NA, 'bar')),         .Names = c('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',             'j'))), .Names = c('x', 'y'));" +
+                        "do.call('identical', argv)");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log10.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log10.java
index 11f19dd5403a7f4c9364119db2c3be4f59bb5790..a7cf88d1a1eacf5fd0e1e9d05c139a66f037154b 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log10.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log10.java
@@ -63,7 +63,7 @@ public class TestBuiltin_log10 extends TestBase {
         assertEval("{ as.integer(log10(200)*100000) } ");
 
         assertEval("{ m <- matrix(1:4, nrow=2) ; round( log10(m), digits=5 )  }");
-        assertEval(Ignored.Unknown, "{ x <- c(a=1, b=10) ; round( c(log(x), log10(x), log2(x)), digits=5 ) }");
+        assertEval("{ x <- c(a=1, b=10) ; round( c(log(x), log10(x), log2(x)), digits=5 ) }");
 
         assertEval("{ log10(c(1+1i, -1-1i)) }");
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pretty.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pretty.java
index 5151c51755823f045cc95948e1b2794b79dbeba0..e539220c8de8c727fd2174d91f79b4ca406baabe 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pretty.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pretty.java
@@ -19,23 +19,21 @@ public class TestBuiltin_pretty extends TestBase {
 
     @Test
     public void testpretty1() {
-        assertEval(Ignored.Unknown, "argv <- list(0L, 3L, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
+        assertEval("argv <- list(0L, 3L, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
     }
 
     @Test
     public void testpretty2() {
-        assertEval(Ignored.Unknown, "argv <- list(-0.03, 1.11, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
+        assertEval("argv <- list(-0.03, 1.11, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
     }
 
     @Test
     public void testpretty3() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(-6.64448090063514e-06, 6.64454021993011e-06, 1, 0, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
+        assertEval("argv <- list(-6.64448090063514e-06, 6.64454021993011e-06, 1, 0, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
     }
 
     @Test
     public void testpretty4() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(1.234e+100, 1.234e+100, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
+        assertEval("argv <- list(1.234e+100, 1.234e+100, 5, 1, 0.75, c(1.5, 2.75), 0); .Internal(pretty(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]]))");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rawToBits.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rawToBits.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8f0a4c56f73c0e74f542fcc942964bbbe25d610
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rawToBits.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.builtins;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+// Checkstyle: stop line length check
+public class TestBuiltin_rawToBits extends TestBase {
+
+    @Test
+    public void testRawToBits() {
+        assertEval("rawToBits(raw(0))");
+        assertEval("rawToBits(raw(10))");
+        assertEval("rawToBits(as.raw(0))");
+        assertEval("rawToBits(as.raw(1))");
+        assertEval("rawToBits(as.raw(255))");
+        assertEval("rawToBits(c(as.raw(1), as.raw(255)))");
+        assertEval("rawToBits(raw(0), raw(1))");
+        assertEval("rawToBits(as.raw(0:255))");
+        assertEval("rawToBits(as.raw(c(0,1,255)))");
+
+        assertEval("rawToBits(as.raw(1)[1])");
+
+        assertEval("rawToBits(0:255)");
+        assertEval("rawToBits(NA)");
+        assertEval("rawToBits(NULL)");
+        assertEval("rawToBits(list(list()))");
+        assertEval("rawToBits(list(NULL))");
+        assertEval("rawToBits(c(NULL))");
+
+        assertEval("rawToBits(integer(0))");
+        assertEval("rawToBits(double(0))");
+
+        assertEval("rawToBits(01)");
+        assertEval("rawToBits('a')");
+
+        assertEval("rawToBits(new.env())");
+        assertEval("rawToBits(environment)");
+        assertEval("rawToBits(stdout())");
+    }
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sign.java
index 11d3565ddd47e8c2ea4c83f23dc23b2a5a512354..c116a18a6446c801c66d22aa5853e87a88a00f93 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sign.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sign.java
@@ -61,4 +61,20 @@ public class TestBuiltin_sign extends TestBase {
     public void testsign9() {
         assertEval("argv <- list(numeric(0));sign(argv[[1]]);");
     }
+
+    @Test
+    public void testsign10() {
+        assertEval("sign(c(FALSE))");
+        assertEval("sign(c(FALSE, TRUE))");
+        assertEval("sign(c(1, -1, FALSE))");
+        assertEval("sign(list(c(1, -1, FALSE))[[1]])");
+        assertEval("sign(1i)");
+        assertEval("sign(c(1, -1, FALSE, 1i))");
+        assertEval("sign('a')");
+        assertEval("sign('1')");
+        assertEval("sign('1L')");
+        assertEval("sign(NULL)");
+        assertEval("sign(NaN)");
+        assertEval("sign(NA_real_)");
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestRandGenerationFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestRandGenerationFunctions.java
index 11898e61ca3b04ff4c2f6eedc78dda28b32b5ab6..6a6b175ea891e7be107607c82849195514ea49d5 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestRandGenerationFunctions.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestRandGenerationFunctions.java
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.test.TestBase;
  * tests for its specific corner cases if those are not covered here.
  */
 public class TestRandGenerationFunctions extends TestBase {
-    private static final String[] FUNCTION2_NAMES = {"rnorm", "runif", "rgamma", "rbeta", "rcauchy", "rf", "rlogis", "rweibull", "rchisq", "rwilcox"};
+    private static final String[] FUNCTION2_NAMES = {"rnorm", "runif", "rgamma", "rbeta", "rcauchy", "rf", "rlogis", "rweibull", "rchisq", "rwilcox", "rlnorm"};
     private static final String[] FUNCTION2_PARAMS = {
                     "10, 10, 10",
                     "20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3)",
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestStatFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestStatFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..d15b49dd4f2a0250212fd7abd5e035e24cb85ffc
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestStatFunctions.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.library.stats;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+/**
+ * Common tests for functions implemented using {@code StatsFunctions} infrastructure.
+ */
+public class TestStatFunctions extends TestBase {
+    private static final String[] FUNCTION3_1_NAMES = {"dgamma", "dbeta", "dcauchy", "dlnorm"};
+    private static final String[] FUNCTION3_1_PARAMS = {
+                    "10, 10, 10, log=TRUE",
+                    "3, 3, 3, log=FALSE",
+                    "c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=TRUE",
+                    "c(-1, 0, 1), c(-1, 0, 0.2, 2:5), rep(c(-1, 0, 0.1, 0.9, 3), 12), log=FALSE",
+                    "0, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0), log=FALSE",
+                    "0, c(0.0653, 0.000123, 32e-80, 8833, 79e70), c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE",
+                    "c(NA, NaN, 1/0, -1/0), 2, 2, log=FALSE"
+    };
+
+    @Test
+    public void testFunctions31() {
+        assertEval(Output.IgnoreWhitespace, template("set.seed(1); %0(%1)", FUNCTION3_1_NAMES, FUNCTION3_1_PARAMS));
+    }
+
+    private static final String[] FUNCTION2_1_NAMES = {"dchisq", "dexp", "dgeom", "dpois", "dt"};
+    private static final String[] FUNCTION2_1_PARAMS = {
+                    "10, 10, log=TRUE",
+                    "3, 3, log=FALSE",
+                    "c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=TRUE",
+                    "c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4), log=FALSE",
+                    "c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), log=FALSE",
+                    "0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), log=FALSE"
+    };
+
+    @Test
+    public void testFunctions21() {
+        assertEval(Output.IgnoreWhitespace, template("set.seed(1); %0(%1)", FUNCTION2_1_NAMES, FUNCTION2_1_PARAMS));
+    }
+
+    private static final String[] FUNCTION2_2_NAMES = {"pchisq", "pexp", "qexp", "qgeom"};
+    private static final String[] FUNCTION2_2_PARAMS = {
+                    "0, 10",
+                    "c(-1, 0, 0.2, 2), rep(c(-1, 0, 0.1, 0.9, 3), 4)",
+                    "0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1)"
+    };
+
+    @Test
+    public void testFunctions22() {
+        // first: the "normal params" with all the combinations of log.p and lower.tail
+        assertEval(Output.IgnoreWhitespace, template("set.seed(1); %0(%1, %2, %3)",
+                        FUNCTION2_2_NAMES, FUNCTION2_2_PARAMS, new String[]{"lower.tail=TRUE", "lower.tail=FALSE"}, new String[]{"log.p=TRUE", "log.p=FALSE"}));
+        // the error cases (where log.p nor lower.tail should make no difference)
+        // first parameter wrong
+        assertEval(Output.IgnoreWhitespace, template("set.seed(1); %0(%1)", FUNCTION2_2_NAMES, new String[]{"c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5)"}));
+        // second parameter wrong
+        assertEval(Output.IgnoreWhitespace, template("set.seed(1); %0(%1)", FUNCTION2_2_NAMES, new String[]{"rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0)"}));
+    }
+
+    private static final String[] FUNCTION3_2_NAMES = {"pbeta", "pcauchy", "qcauchy", "qlnorm", "plnorm"};
+    private static final String[] FUNCTION3_2_PARAMS = {
+                    "0, 10, 10",
+                    "c(-1, 0, 0.2, 2), c(-1, 0, 0.1, 0.9, 3), rep(c(-1, 0, 1, 0.1, -0.1, 0.0001), 20)",
+                    "0, c(0.0653, 0.000123, 32e-80, 8833, 79e70, 0, -1), rep(c(0.0653, 0.000123, 32e-80, 8833, 79e70), 7)"
+    };
+
+    @Test
+    public void testFunctions32() {
+        // first: the "normal params" with all the combinations of log.p and lower.tail
+        assertEval(Output.IgnoreWhitespace, template("set.seed(1); %0(%1, %2, %3)",
+                        FUNCTION3_2_NAMES, FUNCTION3_2_PARAMS, new String[]{"lower.tail=TRUE", "lower.tail=FALSE"}, new String[]{"log.p=TRUE", "log.p=FALSE"}));
+        // the error cases (where log.p nor lower.tail should make no difference)
+        // first parameter wrong
+        assertEval(Output.IgnoreWarningContext,
+                        template("set.seed(1); %0(%1)", FUNCTION3_2_NAMES, new String[]{"c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5)"}));
+        // second parameter wrong
+        assertEval(Output.IgnoreWarningContext,
+                        template("set.seed(1); %0(%1)", FUNCTION3_2_NAMES, new String[]{"rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0), rep(c(1, 0, 0.1), 5)"}));
+        // third parameter wrong
+        assertEval(Output.IgnoreWhitespace, template("set.seed(1); %0(%1)", FUNCTION3_2_NAMES, new String[]{"rep(c(1, 0, 0.1), 5), rep(c(1, 0, 0.1), 5), c(NA, 0, NaN, 1/0, -1/0)"}));
+    }
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestStats.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestStats.java
index 3ab6478a9f128b4f225e287d530217da3861d220..13121b775e0e31a4c03bf5a724f14a9283b2760a 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestStats.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestStats.java
@@ -143,25 +143,21 @@ public class TestStats extends TestBase {
 
         assertEval("{ set.seed(7); round( runif(3), digits = 5 ) }");
         assertEval("{ set.seed(7); round( runif(3,1,10), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( runif(3,1:3,3:2), digits = 5 ) }");
         assertEval("{ set.seed(7); round( rnorm(3,c(1000,2,3),c(10,11)), digits = 5 ) }");
 
         assertEval("{ set.seed(7); round( rbinom(3,3,0.9), digits = 5 ) }");
         assertEval("{ set.seed(7); round( rbinom(3,10,(1:5)/5), digits = 5 ) }");
-    }
-
-    @Test
-    public void testRandomIgnore() {
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( runif(3,1:3,3:2), digits = 5 ) }");
 
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( rgamma(3,1), digits = 5 ) }");
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( rgamma(3,0.5,scale=1:3), digits = 5 ) }");
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( rgamma(3,0.5,rate=1:3), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( rgamma(3,1), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( rgamma(3,0.5,scale=1:3), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( rgamma(3,0.5,rate=1:3), digits = 5 ) }");
 
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( rlnorm(3), digits = 5 ) }");
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( rlnorm(3,sdlog=c(10,3,0.5)), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( rcauchy(3), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( rcauchy(3, scale=4, location=1:3), digits = 5 ) }");
 
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( rcauchy(3), digits = 5 ) }");
-        assertEval(Ignored.Unknown, "{ set.seed(7); round( rcauchy(3, scale=4, location=1:3), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( rlnorm(3), digits = 5 ) }");
+        assertEval("{ set.seed(7); round( rlnorm(3,sdlog=c(10,3,0.5)), digits = 5 ) }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestRFFIPackage.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestRFFIPackage.java
index 1b8cd192ef964076af0a275b3de0b31ace62002a..40270c5de51f4b35661184065b85a52780d0e742 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestRFFIPackage.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestRFFIPackage.java
@@ -43,8 +43,13 @@ public class TestRFFIPackage extends TestRPackages {
         tearDownUninstallTestPackages(TEST_PACKAGES);
     }
 
+    /**
+     * This is somewhat expensive to do per test, but the only alternative is to put all the
+     * micro-tests in one big test. It might be that this should be switched to an R file-based
+     * approach as the number of tests increase.
+     */
     private void assertEvalWithLibWithSetup(String setup, String test) {
-        assertEval(TestBase.template("{ library(\"testrffi\", lib.loc = \"%0\"); " + setup + "x <- " + test + "; detach(\"package:testrffi\"); x }", new String[]{TestRPackages.libLoc()}));
+        assertEval(TestBase.template("{ library(\"testrffi\", lib.loc = \"%0\"); " + setup + "x <- " + test + "; detach(\"package:testrffi\", unload=T); x }", new String[]{TestRPackages.libLoc()}));
     }
 
     private void assertEvalWithLib(String test) {
@@ -86,6 +91,16 @@ public class TestRFFIPackage extends TestRPackages {
         assertEvalWithLib("rffi.null()");
     }
 
+    @Test
+    public void testRFFI7E() {
+        assertEvalWithLib("rffi.null.E()");
+    }
+
+    @Test
+    public void testRFFI7C() {
+        assertEvalWithLib("rffi.null.C()");
+    }
+
     @Test
     public void testRFFI8() {
         assertEvalWithLib("rffi.isRString(character(0))");
@@ -143,6 +158,6 @@ public class TestRFFIPackage extends TestRPackages {
 
     @Test
     public void testRFFI19() {
-        assertEvalWithLibWithSetup("x <- 1; ", "rffi.findVar(x, globalenv())");
+        assertEvalWithLibWithSetup("x <- 1; ", "rffi.findvar(\"x\", globalenv())");
     }
 }
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 34b4bca629f2ceea3857c3c258899c620e4673e9..0467373d319614885a7468b7ad3c4ddd3c190853 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -31,7 +31,7 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java,
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Arithmetic.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinom.java,gnu_r_gentleman_ihaka.copyright
-com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java,gnu_r_ihaka_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cauchy.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java,gnu_r.copyright
@@ -42,7 +42,6 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPQ.java,gnu_r.core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rt.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/GammaFunctions.java,gnu_r_qgamma.copyright
-com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/MathConstants.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/QHyper.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RHyper.java,gnu_r_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/MathInit.java,gnu_r.core.copyright
@@ -57,10 +56,13 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Random2.java
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RPois.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rbinom.java,gnu_r_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java,gnu_r.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Chisq.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java,gnu_r_splines.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctions.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandGenerationFunctions.java,gnu_r_gentleman_ihaka.copyright
-com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java,gnu_r_ihaka.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMath.java,gnu_r_ihaka.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/LogNormal.java,gnu_r_ihaka.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/MathConstants.java,gnu_r_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SNorm.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SExp.java,gnu_r_ihaka_core.copyright
@@ -69,8 +71,12 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNbinomMu.ja
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RLogis.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rf.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RChisq.java,gnu_r_ihaka_core.copyright
-com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RExp.java,gnu_r_ihaka_core.copyright
-com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGeom.java,gnu_r_ihaka_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Exp.java,gnu_r_ihaka_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Geom.java,gnu_r_ihaka_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dt.java,gnu_r.core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Df.java,gnu_r.core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DBeta.java,gnu_r.core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DPois.java,gnu_r.core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RNchisq.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Wilcox.java,gnu_r.core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RWeibull.java,gnu_r_ihaka_core.copyright
@@ -149,12 +155,12 @@ com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/D
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java,purdue.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java,gnu_r.copyright
-com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/DotC.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrdc2.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Fft.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java,gnu_r.copyright
-com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java,gnu_r.copyright
+com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java,gnu_r.copyright
+com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java,gnu_r.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dnorm4.java,gnu_r.copyright
diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py
index 2166292810b8b4f6b8c48aad1d718472f0ef01f9..4003efe2cde967c8fb499814c73639ad8a24837c 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -28,7 +28,7 @@ suite = {
     "suites" : [
             {
                "name" : "truffle",
-               "version" : "f0c06d466056ad23e05aa3d21b98405cd72f117b",
+               "version" : "13641c9f68eefccd0099d283ca25d6bb44b3349a",
                "urls" : [
                     {"url" : "https://github.com/graalvm/truffle", "kind" : "git"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},