diff --git a/.gitignore b/.gitignore
index dd8ad6fc9f8427efea3cd9df3720d9a10af35050..9c8ffbab24c0640598a7a64c358c0658e26b7f38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,8 @@
 /com.oracle.truffle.r.native/library/*/lib/*
 /com.oracle.truffle.r.native/library/stats/src/fft.c
 /com.oracle.truffle.r.native/library/tools/src/gramRd.c
+/com.oracle.truffle.r.native/library/grid/src/grid.c
+/com.oracle.truffle.r.native/library/grid/src/state.c
 /com.oracle.truffle.r.native/platform.mk
 /com.oracle.truffle.r.native/gnur/Makeconf.done
 /com.oracle.truffle.r.native/gnur/platform.mk.temp*
diff --git a/ci.hocon b/ci.hocon
index f0bf56b1e49c5fbb472ab58036fb23fc4b480584..9d80f57bdfee35b5ed75c817ad196986f2f46722 100644
--- a/ci.hocon
+++ b/ci.hocon
@@ -6,7 +6,7 @@
 # java 7 is needed by Truffle (for now)
 java7 : {name : oraclejdk, version : "7",    platformspecific: true}
 # java 8 must be a jvmci enabled variant
-java8 : {name : labsjdk, version : "8u111-jvmci-0.23", platformspecific: true}
+java8 : {name : labsjdk, version : "8u121-jvmci-0.24", platformspecific: true}
 
 java8Downloads : {
   downloads : {
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 86f938fe3be54e41b91c3c8edaaefac88e3b91d6..9f8a4b53b49ee82605bc9579d0c63b009ea9b7ba 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -298,16 +298,18 @@ final class REngine implements Engine, Engine.Timings {
     @Override
     public CallTarget parseToCallTarget(Source source, MaterializedFrame executionFrame) throws ParseException {
         List<RSyntaxNode> statements = parseImpl(source);
-        return Truffle.getRuntime().createCallTarget(new PolyglotEngineRootNode(statements, createSourceSection(statements), executionFrame));
+        return Truffle.getRuntime().createCallTarget(new PolyglotEngineRootNode(statements, createSourceSection(source, statements), executionFrame));
     }
 
-    private static SourceSection createSourceSection(List<RSyntaxNode> statements) {
+    private static SourceSection createSourceSection(Source source, List<RSyntaxNode> statements) {
         // All statements come from the same "Source"
-        if (statements.size() == 1) {
+        if (statements.isEmpty()) {
+            return source.createSection(0, source.getLength());
+        } else if (statements.size() == 1) {
             return statements.get(0).getSourceSection();
         } else {
-            Source source = statements.get(0).getSourceSection().getSource();
-            return source.createSection(0, statements.get(statements.size() - 1).getSourceSection().getCharEndIndex());
+            Source newSource = statements.get(0).getSourceSection().getSource();
+            return newSource.createSection(0, statements.get(statements.size() - 1).getSourceSection().getCharEndIndex());
         }
     }
 
@@ -371,7 +373,7 @@ final class REngine implements Engine, Engine.Timings {
                         CompilerDirectives.transferToInterpreterAndInvalidate();
                         calls[i] = insert(Truffle.getRuntime().createDirectCallNode(doMakeCallTarget(node.asRNode(), RSource.Internal.REPL_WRAPPER.string, printResult, true)));
                     }
-                    lastValue = calls[i].call(frame, new Object[]{executionFrame != null ? executionFrame : newContext.stateREnvironment.getGlobalFrame()});
+                    lastValue = calls[i].call(new Object[]{executionFrame != null ? executionFrame : newContext.stateREnvironment.getGlobalFrame()});
                 }
                 return lastValue;
             } catch (ReturnException ex) {
@@ -551,7 +553,7 @@ final class REngine implements Engine, Engine.Timings {
             VirtualFrame vf = prepareFrame(frame);
             Object result = null;
             try {
-                result = body.execute(vf);
+                result = body.visibleExecute(vf);
                 assert checkResult(result);
                 if (printResult && result != null) {
                     assert topLevel;
@@ -562,7 +564,7 @@ final class REngine implements Engine, Engine.Timings {
                 if (topLevel) {
                     RErrorHandling.printWarnings(suppressWarnings);
                 }
-                setVisibility.executeEndOfFunction(vf, this);
+                setVisibility.executeEndOfFunction(vf);
             } catch (RError e) {
                 CompilerDirectives.transferToInterpreter();
                 throw e;
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 649e80683655b6e50ae51f8aa4fa6d0bec054025..0c7606c8f3ef30a06a7a5c0eecb5c113041a1753 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
@@ -68,7 +68,7 @@ import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntimeASTAccess;
-import com.oracle.truffle.r.runtime.RSource;
+import com.oracle.truffle.r.runtime.RSrcref;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.Engine;
@@ -92,7 +92,6 @@ import com.oracle.truffle.r.runtime.nodes.RCodeBuilder.Argument;
 import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
@@ -133,17 +132,6 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  */
 class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
 
-    private static Object getIntrinsicValue(Object result) {
-        if (result instanceof RSyntaxConstant) {
-            return ((RSyntaxConstant) result).getValue();
-        } else if (result instanceof RSyntaxLookup) {
-            return RDataFactory.createSymbolInterned(((RSyntaxLookup) result).getIdentifier());
-        } else {
-            assert result instanceof RSyntaxCall || result instanceof RSyntaxFunction : result.getClass();
-            return RDataFactory.createLanguage(((RSyntaxNode) result).asRNode());
-        }
-    }
-
     @TruffleBoundary
     @Override
     public RLanguage.RepType getRepType(RLanguage rl) {
@@ -203,7 +191,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
 
                     Object list = RNull.instance;
                     for (int i = sig.getLength() - 1; i >= 0; i--) {
-                        list = RDataFactory.createPairList(defaults[i] == null ? RSymbol.MISSING : getIntrinsicValue(defaults[i]), list,
+                        list = RDataFactory.createPairList(defaults[i] == null ? RSymbol.MISSING : RASTUtils.createLanguageElement(defaults[i]), list,
                                         RDataFactory.createSymbolInterned(sig.getName(i)));
                     }
                     return list;
@@ -212,7 +200,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
                     break;
                 case 3:
                     // srcref
-                    return RSource.createSrcRef(s.getLazySourceSection());
+                    return RSrcref.createLloc(s.getLazySourceSection());
                 default:
                     throw RInternalError.shouldNotReachHere();
             }
@@ -228,7 +216,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         /*
          * Constants and lookups are converted to their intrinsic value:
          */
-        return getIntrinsicValue(result);
+        return RASTUtils.createLanguageElement(result);
     }
 
     @Override
@@ -724,9 +712,8 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         RInstrumentation.checkDebugRequested(func);
     }
 
-    @SuppressWarnings("rawtypes")
     @Override
-    public Class<? extends TruffleLanguage> getTruffleRLanguage() {
+    public Class<? extends TruffleLanguage<?>> getTruffleRLanguage() {
         return TruffleRLanguage.class;
     }
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
index 29ecac04ed499a9fc048931f81ae6a59b4ff1371..c6ead8aaa2a9849ee64a13b67167ae541313634b 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.instrumentation.ProvidedTags;
 import com.oracle.truffle.api.instrumentation.StandardTags;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.engine.interop.RForeignAccessFactoryImpl;
 import com.oracle.truffle.r.nodes.RASTBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages;
@@ -45,15 +46,16 @@ import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RAccuracyInfo;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.RVersionInfo;
-import com.oracle.truffle.r.runtime.TempPathName;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.Engine.IncompleteSourceException;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.RCloseable;
-import com.oracle.truffle.r.runtime.ffi.Load_RFFIFactory;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RPromise;
+import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * Only does the minimum for running under the debugger. It is not completely clear how to correctly
@@ -70,12 +72,9 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
      */
     private static void initialize() {
         try {
-            Load_RFFIFactory.initialize(true);
+            RFFIFactory.initialize();
             Locale.setDefault(Locale.ROOT);
             RAccuracyInfo.initialize();
-            RVersionInfo.initialize();
-            TempPathName.initialize();
-
         } catch (Throwable t) {
             t.printStackTrace();
             /*
@@ -137,6 +136,12 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
         if (value instanceof String) {
             return (String) value;
         }
+        if (value instanceof RPromise) {
+            RPromise promise = (RPromise) value;
+            if (promise.isEvaluated()) {
+                value = promise.getValue();
+            }
+        }
         return RRuntime.toString(value);
     }
 
@@ -149,6 +154,39 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
         return false;
     }
 
+    @Override
+    protected Object findMetaObject(RContext context, Object value) {
+        Object unwrappedValue = value;
+        if (unwrappedValue instanceof RPromise) {
+            RPromise promise = (RPromise) unwrappedValue;
+            if (promise.isEvaluated()) {
+                unwrappedValue = promise.getValue();
+            }
+        }
+        unwrappedValue = RRuntime.asAbstractVector(unwrappedValue); // Wrap scalars "Integer",
+                                                                    // "Double" etc.
+        if (unwrappedValue instanceof RTypedValue) {
+            return ((RTypedValue) unwrappedValue).getRType().getName();
+        } else {
+            return "Object";
+        }
+    }
+
+    @Override
+    protected SourceSection findSourceLocation(RContext context, Object value) {
+        if (value instanceof RPromise) {
+            RPromise promise = (RPromise) value;
+            RBaseNode expr = promise.getClosure().getExpr();
+            return expr.getEncapsulatingSourceSection();
+        }
+
+        if (value instanceof RFunction) {
+            RFunction f = (RFunction) value;
+            return f.getTarget().getRootNode().getSourceSection();
+        }
+        return null;
+    }
+
     @SuppressWarnings("try")
     @Override
     protected CallTarget parse(ParsingRequest request) throws Exception {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNodeHelper.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/CharSXPWrapperMR.java
similarity index 57%
rename from com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNodeHelper.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/CharSXPWrapperMR.java
index 29e9f0bdcc9454eb6a7cbb995c3c5cf64dec9792..4e5a73a607ee27689111a5307a3b0b33d95baf1c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNodeHelper.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/CharSXPWrapperMR.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,23 +20,23 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.nodes.access;
+package com.oracle.truffle.r.engine.interop;
 
-import com.oracle.truffle.api.frame.MaterializedFrame;
-import com.oracle.truffle.api.frame.VirtualFrame;
+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.CharSXPWrapper;
 
-/**
- * Helper class for the WriteSuperFrame variants. This ought to be a static class in
- * {@link WriteSuperFrameVariableNode} but that causes compilation problems.
- */
-abstract class WriteSuperFrameVariableNodeHelper extends BaseWriteVariableNode {
-
-    public abstract void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame);
+@MessageResolution(receiverType = CharSXPWrapper.class, language = TruffleRLanguage.class)
+public class CharSXPWrapperMR {
+    @CanResolve
+    public abstract static class CharSXPWrapperCheck extends Node {
 
-    @Override
-    public final Object execute(VirtualFrame frame) {
-        Object value = getRhs().execute(frame);
-        execute(frame, value);
-        return value;
+        protected static boolean test(TruffleObject receiver) {
+            return receiver instanceof CharSXPWrapper;
+        }
     }
+
 }
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 11559c31bc4ad818a8b31b6a04defef4ba89cb84..1b8aca885df504ab57b6b46bcac74eec7523a8b6 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,11 +22,8 @@
  */
 package com.oracle.truffle.r.engine.interop;
 
-import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-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;
@@ -36,31 +33,20 @@ 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.RDouble;
-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.RInteger;
 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.CharSXPWrapper;
 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
@@ -72,16 +58,6 @@ import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
  * 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
@@ -89,196 +65,90 @@ import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol;
  *
  */
 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,
-                    NativeRawArray.class, NativeCharArray.class, NativeIntegerArray.class,
-                    NativeDoubleArray.class, NativeLogicalArray.class,
-                    RDouble.class, RInteger.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; // for sanity check
+        private final ForeignAccess 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.
+         * {@link PolyglotEngine} checks the thread on a {@link ForeignAccess}.
          */
         private final Thread thread;
 
-        private ForeignAccessState() {
+        private TableEntry(Class<? extends RTruffleObject> clazz, ForeignAccess foreignAccess) {
+            this.clazz = clazz;
+            this.foreignAccess = foreignAccess;
             this.thread = Thread.currentThread();
-            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));
-                }
-            }
-        }
-
-        private ForeignAccess get(RTruffleObject obj) {
-            Class<? extends RTruffleObject> clazz = obj.getClass();
-            return get(clazz);
         }
+    }
 
-        private ForeignAccess get(Class<? extends RTruffleObject> clazz) {
-            int index = System.identityHashCode(clazz) & tableMask;
-            assert table[index].clazz == clazz;
-            return table[index].foreignAccess;
-        }
+    private final TableEntry[] table = new TableEntry[32];
+    int tableIndex;
 
-        static {
-            generatePrototypeTable();
-        }
-
-        /**
-         * 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;
-                }
+    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;
             }
-            tableMask = ts - 1;
         }
+        return createForeignAccess(objclazz);
+    }
 
-        @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 if (NativeRawArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeRawArrayMRForeign.createAccess();
-            } else if (NativeLogicalArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeLogicalArrayMRForeign.createAccess();
-            } else if (NativeCharArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeCharArrayMRForeign.createAccess();
-            } else if (NativeDoubleArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeDoubleArrayMRForeign.createAccess();
-            } else if (NativeIntegerArray.class.isAssignableFrom(clazz)) {
-                foreignAccess = NativeIntegerArrayMRForeign.createAccess();
-            } else if (RInteger.class.isAssignableFrom(clazz)) {
-                foreignAccess = RIntegerMRForeign.createAccess();
-            } else if (RDouble.class.isAssignableFrom(clazz)) {
-                foreignAccess = RDoubleMRForeign.createAccess();
+    @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 if (NativeRawArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeRawArrayMRForeign.createAccess();
+        } else if (NativeLogicalArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeLogicalArrayMRForeign.createAccess();
+        } else if (NativeCharArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeCharArrayMRForeign.createAccess();
+        } else if (NativeDoubleArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeDoubleArrayMRForeign.createAccess();
+        } else if (NativeIntegerArray.class.isAssignableFrom(clazz)) {
+            foreignAccess = NativeIntegerArrayMRForeign.createAccess();
+        } else if (RInteger.class.isAssignableFrom(clazz)) {
+            foreignAccess = RIntegerMRForeign.createAccess();
+        } else if (RDouble.class.isAssignableFrom(clazz)) {
+            foreignAccess = RDoubleMRForeign.createAccess();
+        } else if (CharSXPWrapper.class.isAssignableFrom(clazz)) {
+            foreignAccess = CharSXPWrapperMRForeign.createAccess();
+        } else {
+            if (RAbstractVector.class.isAssignableFrom(clazz)) {
+                foreignAccess = ForeignAccess.create(RAbstractVector.class, new RAbstractVectorAccessFactory());
             } else {
-                if (RAbstractVector.class.isAssignableFrom(clazz)) {
-                    foreignAccess = ForeignAccess.create(RAbstractVector.class, new RAbstractVectorAccessFactory());
-                } else {
-                    throw RInternalError.unimplemented("foreignAccess: " + name);
-                }
+                throw RInternalError.unimplemented("foreignAccess: " + name);
             }
-            return foreignAccess;
         }
+        return 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;
+        return get(obj);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleC.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_C.java
similarity index 77%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleC.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_C.java
index 9c5d86b065c1187113c9664dd7b705afdad03553..89fb551c08e14b756f3e1b8d847d3093aee06dc7 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleC.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_C.java
@@ -20,9 +20,8 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
-import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.nodes.Node;
@@ -32,23 +31,21 @@ import com.oracle.truffle.r.engine.interop.NativeRawArray;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
-import com.oracle.truffle.r.runtime.ffi.jni.JNI_C;
-import com.oracle.truffle.r.runtime.ffi.truffle.TruffleRFFIFrameHelper;
+import com.oracle.truffle.r.runtime.ffi.jni.JNI_C.JNI_InvokeCNode;
 
-class TruffleC implements CRFFI {
-    private static class TruffleCRFFINode extends JNI_C.JNI_CRFFINode {
+class TruffleLLVM_C implements CRFFI {
+    private static class TruffleLLVM_InvokeCNode extends JNI_InvokeCNode {
 
         @Override
-        public synchronized void invoke(NativeCallInfo nativeCallInfo, Object[] args) {
+        public synchronized void execute(NativeCallInfo nativeCallInfo, Object[] args) {
             if (nativeCallInfo.address.value instanceof Long) {
-                super.invoke(nativeCallInfo, args);
+                super.execute(nativeCallInfo, args);
             } else {
-                VirtualFrame frame = TruffleRFFIFrameHelper.create();
-                TruffleDLL.ensureParsed(nativeCallInfo);
+                TruffleLLVM_DLL.ensureParsed(nativeCallInfo);
                 Object[] wargs = wrap(args);
                 try {
                     Node messageNode = Message.createExecute(0).createNode();
-                    ForeignAccess.sendExecute(messageNode, frame, nativeCallInfo.address.asTruffleObject(), wargs);
+                    ForeignAccess.sendExecute(messageNode, nativeCallInfo.address.asTruffleObject(), wargs);
                 } catch (Throwable t) {
                     throw RInternalError.shouldNotReachHere(t);
                 }
@@ -76,7 +73,7 @@ class TruffleC implements CRFFI {
     }
 
     @Override
-    public CRFFINode createCRFFINode() {
-        return new TruffleCRFFINode();
+    public InvokeCNode createInvokeCNode() {
+        return new TruffleLLVM_InvokeCNode();
     }
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCAccess.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_CAccess.java
similarity index 60%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCAccess.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_CAccess.java
index 8fc6bd51721bec5f74b62b3eda047f5c0e0d2f12..16f57a750e1f42de0a24077faf6f9109547ed6ad 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCAccess.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_CAccess.java
@@ -20,16 +20,23 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
 import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
+import com.oracle.truffle.r.runtime.ffi.jni.JNI_DLL;
+import com.oracle.truffle.r.runtime.rng.user.UserRNG;
 
 /**
- * Access to primitive C operations.
+ * Access to some primitive C operations. This is required by the {@link UserRNG} API which works
+ * with {@code double *}.
+ *
+ * N.B. When {@code libR} is not completely in LLVM mode (as now), we have to look up the symbols
+ * using an explicitly created {@link TruffleLLVM_DLL.LLVM_Handle} and not go via generic lookup in
+ * {@link DLL} as that would use a {@link JNI_DLL} handle.
  */
-public class TruffleCAccess {
-    private static final TruffleDLL.TruffleHandle handle = new TruffleDLL.TruffleHandle("libR");
+public class TruffleLLVM_CAccess {
+    private static final TruffleLLVM_DLL.LLVM_Handle handle = new TruffleLLVM_DLL.LLVM_Handle("libR", null);
 
     public enum Function {
         READ_POINTER_INT,
@@ -41,7 +48,10 @@ public class TruffleCAccess {
 
         public DLL.SymbolHandle getSymbolHandle() {
             if (symbolHandle == null) {
-                symbolHandle = RFFIFactory.getRFFI().getDLLRFFI().dlsym(handle, cName());
+                // This would be the generic path
+                // symbolHandle = DLL.findSymbol(cName(), null);
+                symbolHandle = (DLL.SymbolHandle) DLLRFFI.DLSymRootNode.create().getCallTarget().call(handle, cName());
+                assert symbolHandle != null;
             }
             return symbolHandle;
         }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCall.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_Call.java
similarity index 72%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCall.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_Call.java
index 5fd056c445db51ec1bd1eba916d7c1780a689e53..9b76276804be7dacb87f9e4d2d16712eea905654 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCall.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_Call.java
@@ -20,19 +20,18 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.r.engine.interop.ffi.TruffleCallFactory.InvokeTruffleNodeGen;
-import com.oracle.truffle.r.engine.interop.ffi.TruffleCallFactory.SplitTruffleCallRFFINodeGen;
+import com.oracle.truffle.r.engine.interop.ffi.llvm.TruffleLLVM_CallFactory.InvokeTruffleNodeGen;
+import com.oracle.truffle.r.engine.interop.ffi.llvm.TruffleLLVM_CallFactory.SplitTruffleCallRFFINodeGen;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
@@ -40,23 +39,21 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
 import com.oracle.truffle.r.runtime.ffi.jni.JNI_Call;
-import com.oracle.truffle.r.runtime.ffi.jni.JNI_Call.JNI_CallRFFINode;
-import com.oracle.truffle.r.runtime.ffi.truffle.TruffleRFFIFrameHelper;
 
-class TruffleCall implements CallRFFI {
-    private static TruffleCall truffleCall;
+class TruffleLLVM_Call implements CallRFFI {
+    private static TruffleLLVM_Call truffleCall;
     private static TruffleObject truffleCallTruffleObject;
     private static TruffleObject truffleCallHelper;
 
     @SuppressWarnings("unused")
-    TruffleCall() {
+    TruffleLLVM_Call() {
         new JNI_Call();
         truffleCall = this;
         truffleCallTruffleObject = JavaInterop.asTruffleObject(truffleCall);
-        TrufflePkgInit.initialize();
-        truffleCallHelper = TruffleCallHelper.initialize();
+        truffleCallHelper = TruffleLLVM_UpCallsRFFIImpl.initialize();
     }
 
     static class ContextStateImpl implements RContext.ContextState {
@@ -66,6 +63,7 @@ class TruffleCall implements CallRFFI {
         @Override
         public ContextState initialize(RContext contextA) {
             this.context = contextA;
+            RFFIFactory.getRFFI().getCallRFFI();
             context.addExportedSymbol("_fastr_rffi_call", truffleCallTruffleObject);
             context.addExportedSymbol("_fastr_rffi_callhelper", truffleCallHelper);
             return this;
@@ -81,7 +79,6 @@ class TruffleCall implements CallRFFI {
     }
 
     private enum INIT_VAR_FUN {
-        OBJ,
         DOUBLE,
         INT;
 
@@ -96,13 +93,14 @@ class TruffleCall implements CallRFFI {
     private static void initVariables(RContext context) {
         // must have parsed the variables module in libR
         for (INIT_VAR_FUN initVarFun : INIT_VAR_FUN.values()) {
-            TruffleDLL.ensureParsed("libR", initVarFun.funName, true);
+            TruffleLLVM_DLL.ensureParsed("libR", initVarFun.funName, true);
             initVarFun.symbolHandle = new SymbolHandle(context.getEnv().importSymbol("@" + initVarFun.funName));
         }
-        VirtualFrame frame = TruffleRFFIFrameHelper.create();
         Node executeNode = Message.createExecute(2).createNode();
-        RFFIVariables[] variables = RFFIVariables.values();
+        RFFIVariables[] variables = RFFIVariables.initialize();
         for (int i = 0; i < variables.length; i++) {
+            // The TruffleObject instances are not passed down as
+            // they cannot be stored in memory at the moment
             RFFIVariables var = variables[i];
             Object value = var.getValue();
             if (value == null) {
@@ -110,13 +108,9 @@ class TruffleCall implements CallRFFI {
             }
             try {
                 if (value instanceof Double) {
-                    ForeignAccess.sendExecute(executeNode, frame, INIT_VAR_FUN.DOUBLE.symbolHandle.asTruffleObject(), i, value);
+                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.DOUBLE.symbolHandle.asTruffleObject(), i, value);
                 } else if (value instanceof Integer) {
-                    ForeignAccess.sendExecute(executeNode, frame, INIT_VAR_FUN.INT.symbolHandle.asTruffleObject(), i, value);
-                } else {
-                    // TODO
-                    // ForeignAccess.sendExecute(executeNode, frame,
-                    // INIT_VAR_FUN.OBJ.symbolHandle.asTruffleObject(), i, value);
+                    ForeignAccess.sendExecute(executeNode, INIT_VAR_FUN.INT.symbolHandle.asTruffleObject(), i, value);
                 }
             } catch (Throwable t) {
                 throw RInternalError.shouldNotReachHere(t);
@@ -124,15 +118,19 @@ class TruffleCall implements CallRFFI {
         }
     }
 
-    public static class InvokeJNI extends Node {
-        @Child JNI_CallRFFINode jniCall = new JNI_CallRFFINode();
+    public static class InvokeJNICall extends Node {
+        @Child CallRFFI.InvokeCallNode jniCall = new JNI_Call.JNI_InvokeCallNode();
 
-        public Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args) {
-            return jniCall.invokeCall(nativeCallInfo, args);
+        public Object execute(NativeCallInfo nativeCallInfo, Object[] args) {
+            return jniCall.execute(nativeCallInfo, args);
         }
+    }
+
+    public static class InvokeJNIVoidCall extends Node {
+        @Child CallRFFI.InvokeVoidCallNode jniCall = new JNI_Call.JNI_InvokeVoidCallNode();
 
-        public Object invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args) {
-            jniCall.invokeVoidCall(nativeCallInfo, args);
+        public Object execute(NativeCallInfo nativeCallInfo, Object[] args) {
+            jniCall.execute(nativeCallInfo, args);
             return RNull.instance;
         }
     }
@@ -156,23 +154,22 @@ class TruffleCall implements CallRFFI {
             return doInvoke(messageNode, nativeCallInfo, args);
         }
 
-        @Specialization(contains = "invokeCallCached")
+        @Specialization(replaces = "invokeCallCached")
         protected Object invokeCallNormal(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") RContext context) {
             return doInvoke(Message.createExecute(0).createNode(), nativeCallInfo, args);
         }
 
         private static Object doInvoke(Node messageNode, NativeCallInfo nativeCallInfo, Object[] args) {
-            VirtualFrame frame = TruffleRFFIFrameHelper.create();
             try {
-                return ForeignAccess.sendExecute(messageNode, frame, nativeCallInfo.address.asTruffleObject(), args);
+                return ForeignAccess.sendExecute(messageNode, nativeCallInfo.address.asTruffleObject(), args);
             } catch (Throwable t) {
                 throw RInternalError.shouldNotReachHere(t);
             }
         }
 
         public static boolean ensureReady(NativeCallInfo nativeCallInfo) {
-            TruffleDLL.ensureParsed(nativeCallInfo);
-            ContextStateImpl contextState = TruffleRFFIContextState.getContextState().callState;
+            TruffleLLVM_DLL.ensureParsed(nativeCallInfo);
+            ContextStateImpl contextState = TruffleLLVM_RFFIContextState.getContextState().callState;
             if (!contextState.initVariablesDone) {
                 initVariables(contextState.context);
                 contextState.initVariablesDone = true;
@@ -193,15 +190,15 @@ class TruffleCall implements CallRFFI {
 
         @Specialization(guards = {"isJNICall(nativeCallInfo)", "!voidCall"})
         protected Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean voidCall,
-                        @Cached("new()") InvokeJNI invokeJNI) {
-            return invokeJNI.invokeCall(nativeCallInfo, args);
+                        @Cached("new()") InvokeJNICall invokeJNI) {
+            return invokeJNI.execute(nativeCallInfo, args);
 
         }
 
         @Specialization(guards = {"isJNICall(nativeCallInfo)", "voidCall"})
         protected Object invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") boolean voidCall,
-                        @Cached("new()") InvokeJNI invokeJNI) {
-            return invokeJNI.invokeVoidCall(nativeCallInfo, args);
+                        @Cached("new()") InvokeJNICall invokeJNI) {
+            return invokeJNI.execute(nativeCallInfo, args);
 
         }
 
@@ -216,31 +213,24 @@ class TruffleCall implements CallRFFI {
         }
     }
 
-    private static class TruffleCallRFFINode extends CallRFFINode {
+    private static class TruffleLLVM_InvokeCallNode extends InvokeCallNode {
         @Child SplitTruffleCallRFFINode splitTruffleCallRFFINode = SplitTruffleCallRFFINodeGen.create();
 
         @Override
-        public synchronized Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args) {
+        public synchronized Object execute(NativeCallInfo nativeCallInfo, Object[] args) {
             return splitTruffleCallRFFINode.execute(nativeCallInfo, args, false);
 
         }
+    }
 
-        @Override
-        public synchronized void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args) {
-            splitTruffleCallRFFINode.execute(nativeCallInfo, args, true);
-        }
+    private static class TruffleLLVM_InvokeVoidCallNode extends InvokeVoidCallNode {
+        @Child SplitTruffleCallRFFINode splitTruffleCallRFFINode = SplitTruffleCallRFFINodeGen.create();
 
         @Override
-        public void setTempDir(String tempDir) {
-            // TODO Truffleize
-            new JNI_CallRFFINode().setTempDir(tempDir);
+        public synchronized void execute(NativeCallInfo nativeCallInfo, Object[] args) {
+            splitTruffleCallRFFINode.execute(nativeCallInfo, args, true);
         }
 
-        @Override
-        public void setInteractive(boolean interactive) {
-            // TODO Truffleize
-            new JNI_CallRFFINode().setInteractive(interactive);
-        }
     }
 
     /**
@@ -253,7 +243,12 @@ class TruffleCall implements CallRFFI {
     }
 
     @Override
-    public CallRFFINode createCallRFFINode() {
-        return new TruffleCallRFFINode();
+    public InvokeCallNode createInvokeCallNode() {
+        return new TruffleLLVM_InvokeCallNode();
+    }
+
+    @Override
+    public InvokeVoidCallNode createInvokeVoidCallNode() {
+        return new TruffleLLVM_InvokeVoidCallNode();
     }
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleDLL.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_DLL.java
similarity index 69%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleDLL.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_DLL.java
index 60a2e4e00ee28115ad70ee83e550dd8e70533e53..13eeb36eb0f4fcbb7ef9a53834e35b2d4e477ae8 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleDLL.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_DLL.java
@@ -20,9 +20,10 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
 import java.nio.file.FileSystems;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -35,6 +36,7 @@ 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.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
@@ -42,9 +44,9 @@ import com.oracle.truffle.r.runtime.ffi.jni.JNI_DLL;
 import com.oracle.truffle.r.runtime.ffi.truffle.LLVM_IR;
 
 /**
- * The Truffle version of {@link DLLRFFI}. {@link TruffleDLL#dlopen} expects to find the LLVM IR
- * embedded in the shared library. If it exists it is used, unless the library is blacklisted.
- * Otherwise we fall back to the standard JNI implementation.
+ * The Truffle version of {@link DLLRFFI}. {@code dlopen} expects to find the LLVM IR embedded in
+ * the shared library. If it exists it is used, unless the library is blacklisted. Otherwise we fall
+ * back to the standard JNI implementation.
  *
  * The LLVM bitcode is stored (opaquely) in the shared library file, and access through the
  * {@link LLVM_IR} class. The {@link LLVM_IR#getLLVMIR(String)} method will return an array of
@@ -80,7 +82,7 @@ import com.oracle.truffle.r.runtime.ffi.truffle.LLVM_IR;
  * native code is used by non-LLVM packages (libraries) and the LLVM code is used by the LLVM
  * packages (libraries).
  */
-class TruffleDLL extends JNI_DLL implements DLLRFFI {
+class TruffleLLVM_DLL extends JNI_DLL implements DLLRFFI {
     /**
      * Supports lazy parsing of LLVM modules.
      */
@@ -111,7 +113,7 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
         }
     }
 
-    class ContextStateImpl implements RContext.ContextState {
+    static class ContextStateImpl implements RContext.ContextState {
         /**
          * A map from function name to its {@link ParseStatus}, allowing fast determination whether
          * parsing is required in a call, see {@link #ensureParsed}. N.B. parsing happens at the
@@ -128,9 +130,21 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
          */
         @Override
         public ContextState initialize(RContext context) {
-            for (LLVM_IR ir : libRModules) {
+            for (LLVM_IR ir : truffleDLL.libRModules) {
                 addExportsToMap(this, "libR", ir, (name) -> name.endsWith("_llvm"));
             }
+            if (context.getKind() == RContext.ContextKind.SHARE_PARENT_RW) {
+                // must propagate all LLVM library exports
+                ArrayList<DLLInfo> loadedDLLs = DLL.getLoadedDLLs();
+                for (DLLInfo dllInfo : loadedDLLs) {
+                    if (dllInfo.handle instanceof LLVM_Handle) {
+                        LLVM_Handle llvmHandle = (LLVM_Handle) dllInfo.handle;
+                        for (LLVM_IR ir : llvmHandle.irs) {
+                            addExportsToMap(this, llvmHandle.libName, ir, (name) -> true);
+                        }
+                    }
+                }
+            }
             return this;
         }
 
@@ -142,20 +156,15 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
         }
     }
 
-    private static TruffleDLL truffleDLL;
+    private static TruffleLLVM_DLL truffleDLL;
 
-    TruffleDLL() {
+    TruffleLLVM_DLL() {
         assert truffleDLL == null;
         truffleDLL = this;
     }
 
-    static TruffleDLL getInstance() {
-        assert truffleDLL != null;
-        return truffleDLL;
-    }
-
     static ContextStateImpl newContextState() {
-        return truffleDLL.new ContextStateImpl();
+        return new ContextStateImpl();
     }
 
     static boolean isBlacklisted(String libName) {
@@ -173,11 +182,13 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
         return true;
     }
 
-    static class TruffleHandle {
+    static class LLVM_Handle {
         private final String libName;
+        private final LLVM_IR[] irs;
 
-        TruffleHandle(String libName) {
+        LLVM_Handle(String libName, LLVM_IR[] irs) {
             this.libName = libName;
+            this.irs = irs;
         }
     }
 
@@ -186,35 +197,89 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
         boolean match(String name);
     }
 
-    /**
-     * If a library is enabled for LLVM,the IR for all the modules is retrieved and analyzed. Every
-     * exported symbol in the module added to the parseStatus map for the current {@link RContext}.
-     * This allows {@link #dlsym} to definitively locate any symbol, even if the IR has not been
-     * parsed yet.
-     */
-    @Override
-    public Object dlopen(String path, boolean local, boolean now) {
-        try {
-            LLVM_IR[] irs = LLVM_IR.getLLVMIR(path);
-            String libName = getLibName(path);
-            // even if libR is not all LLVM executed, some parts have to be
-            // but they can't be parsed now
-            if (libName.equals("libR")) {
-                libRModules = irs;
+    private static class TruffleLLVM_DLOpenNode extends JNI_DLOpenNode {
+
+        /**
+         * If a library is enabled for LLVM, the IR for all the modules is retrieved and analyzed.
+         * Every exported symbol in the module added to the parseStatus map for the current
+         * {@link RContext}. This allows {@code dlsym} to definitively locate any symbol, even if
+         * the IR has not been parsed yet.
+         */
+        @Override
+        public Object execute(String path, boolean local, boolean now) {
+            try {
+                LLVM_IR[] irs = LLVM_IR.getLLVMIR(path);
+                String libName = getLibName(path);
+                // even if libR is not all LLVM executed, some parts have to be
+                // but they can't be parsed now
+                if (libName.equals("libR")) {
+                    truffleDLL.libRModules = irs;
+                }
+                if (irs == null || isBlacklisted(libName)) {
+                    return super.execute(path, local, now);
+                } else {
+                    ContextStateImpl contextState = getContextState();
+                    for (int i = 0; i < irs.length; i++) {
+                        LLVM_IR ir = irs[i];
+                        addExportsToMap(contextState, libName, ir, (name) -> true);
+                    }
+                    return new LLVM_Handle(libName, irs);
+                }
+            } catch (Exception ex) {
+                return null;
             }
-            if (irs == null || isBlacklisted(libName)) {
-                return super.dlopen(path, local, now);
-            } else {
-                ContextStateImpl contextState = getContextState();
-                for (int i = 0; i < irs.length; i++) {
-                    LLVM_IR ir = irs[i];
-                    addExportsToMap(contextState, libName, ir, (name) -> true);
+        }
+    }
+
+    private static class TruffleLLVM_DLSymNode extends JNI_DLSymNode {
+        @Override
+        public SymbolHandle execute(Object handle, String symbol) throws UnsatisfiedLinkError {
+            if (handle instanceof LLVM_Handle) {
+                // If the symbol exists it will be in the map
+                ParseStatus parseStatus = getContextState().parseStatusMap.get(symbol);
+                if (parseStatus != null && parseStatus.libName.equals(((LLVM_Handle) handle).libName)) {
+                    // force a parse so we have a "value"
+                    if (!parseStatus.parsed) {
+                        ensureParsed(parseStatus.libName, symbol, true);
+                    }
+                    Object symValue = RContext.getInstance().getEnv().importSymbol("@" + symbol);
+                    assert symValue != null;
+                    return new SymbolHandle(symValue);
+                } else {
+                    // symbol not found (or not in requested library)
+                    throw new UnsatisfiedLinkError();
                 }
-                return new TruffleHandle(libName);
+            } else {
+                return super.execute(handle, symbol);
+            }
+        }
+    }
+
+    private static class TruffleLLVM_DLCloseNode extends JNI_DLCloseNode {
+        @Override
+        public int execute(Object handle) {
+            if (handle instanceof LLVM_Handle) {
+                return 0;
+            } else {
+                return super.execute(handle);
             }
-        } catch (Exception ex) {
-            return null;
         }
+
+    }
+
+    @Override
+    public DLOpenNode createDLOpenNode() {
+        return new TruffleLLVM_DLOpenNode();
+    }
+
+    @Override
+    public DLSymNode createDLSymNode() {
+        return new TruffleLLVM_DLSymNode();
+    }
+
+    @Override
+    public DLCloseNode createDLCloseNode() {
+        return new TruffleLLVM_DLCloseNode();
     }
 
     private static void addExportsToMap(ContextStateImpl contextState, String libName, LLVM_IR ir, ModuleNameMatch moduleNameMatch) {
@@ -239,14 +304,14 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
     private LLVM_IR[] libRModules;
 
     private static ContextStateImpl getContextState() {
-        return TruffleRFFIContextState.getContextState().dllState;
+        return TruffleLLVM_RFFIContextState.getContextState().dllState;
     }
 
     /**
      * About to invoke the (external) function denoted by {@code nativeCallInfo}. Therefore, it must
-     * have been parsed (in {@link #dlsym(Object, String)}) AND all dependent modules, recursively,
-     * must also be parsed. Evidently since the dependencies are expressed at a module level, this
-     * may parse more than strictly necessary.
+     * have been parsed (in {code dlsym}) AND all dependent modules, recursively, must also be
+     * parsed. Evidently since the dependencies are expressed at a module level, this may parse more
+     * than strictly necessary.
      *
      * @param nativeCallInfo
      */
@@ -257,8 +322,6 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
     /**
      * Similar to {@link #ensureParsed(NativeCallInfo)} but with a function specified as a string
      * (for internal use) and an optional check whether the function must exist.
-     *
-     * @param libName TODO
      */
     @TruffleBoundary
     static void ensureParsed(String libName, String name, boolean fatalIfMissing) {
@@ -315,34 +378,4 @@ class TruffleDLL extends JNI_DLL implements DLLRFFI {
         return result;
     }
 
-    @Override
-    public SymbolHandle dlsym(Object handle, String symbol) {
-        if (handle instanceof TruffleHandle) {
-            // If the symbol exists it will be in the map
-            ParseStatus parseStatus = getContextState().parseStatusMap.get(symbol);
-            if (parseStatus != null && parseStatus.libName.equals(((TruffleHandle) handle).libName)) {
-                // force a parse so we have a "value"
-                if (!parseStatus.parsed) {
-                    ensureParsed(parseStatus.libName, symbol, true);
-                }
-                Object symValue = RContext.getInstance().getEnv().importSymbol("@" + symbol);
-                assert symValue != null;
-                return new SymbolHandle(symValue);
-            } else {
-                // symbol not found (or not in requested library)
-                return null;
-            }
-        } else {
-            return super.dlsym(handle, symbol);
-        }
-    }
-
-    @Override
-    public int dlclose(Object handle) {
-        if (handle instanceof TruffleHandle) {
-            return 0;
-        } else {
-            return super.dlclose(handle);
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TrufflePkgInit.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_PkgInit.java
similarity index 89%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TrufflePkgInit.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_PkgInit.java
index 26d01e6f739901449907ca802c2fd8c5c5a16341..6c4b235ca5d9d86afc256813a820c6cf21d21811 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TrufflePkgInit.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_PkgInit.java
@@ -20,9 +20,8 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
-import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.interop.TruffleObject;
@@ -35,16 +34,16 @@ 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;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.ffi.truffle.TruffleRFFIFrameHelper;
 
-class TrufflePkgInit {
+class TruffleLLVM_PkgInit {
 
-    private static TrufflePkgInit trufflePkgInit;
+    private static TruffleLLVM_PkgInit trufflePkgInit;
     private static TruffleObject trufflePkgInitTruffleObject;
 
     static class ContextStateImpl implements RContext.ContextState {
         @Override
         public ContextState initialize(RContext context) {
+            TruffleLLVM_PkgInit.initialize();
             context.addExportedSymbol("_fastr_rffi_pkginit", trufflePkgInitTruffleObject);
             return this;
         }
@@ -58,9 +57,9 @@ class TrufflePkgInit {
         return new ContextStateImpl();
     }
 
-    static TrufflePkgInit initialize() {
+    private static TruffleLLVM_PkgInit initialize() {
         if (trufflePkgInit == null) {
-            trufflePkgInit = new TrufflePkgInit();
+            trufflePkgInit = new TruffleLLVM_PkgInit();
             trufflePkgInitTruffleObject = JavaInterop.asTruffleObject(trufflePkgInit);
         }
         return trufflePkgInit;
@@ -77,11 +76,10 @@ class TrufflePkgInit {
     }
 
     private static Object setSymbol(int nstOrd, long routines, int index, SymbolHandle symbolHandle) {
-        VirtualFrame frame = TruffleRFFIFrameHelper.create();
         Node executeNode = Message.createExecute(3).createNode();
         try {
 
-            Object result = ForeignAccess.sendExecute(executeNode, frame, symbolHandle.asTruffleObject(), nstOrd, routines, index);
+            Object result = ForeignAccess.sendExecute(executeNode, symbolHandle.asTruffleObject(), nstOrd, routines, index);
             return result;
         } catch (Throwable t) {
             throw RInternalError.shouldNotReachHere();
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleRFFIContextState.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_RFFIContextState.java
similarity index 64%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleRFFIContextState.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_RFFIContextState.java
index 4df65f0d27c3b9f6d3241ef26a3353fa9f3b7590..9caaec171979d011110a3f065fdc896070804d68 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleRFFIContextState.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_RFFIContextState.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
@@ -29,29 +29,32 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextState;
  * A facade for the context state for the Truffle LLVM factory. Delegates to the various
  * module-specific pieces of state. This may get merged into a single instance eventually.
  */
-class TruffleRFFIContextState implements ContextState {
-    TruffleDLL.ContextStateImpl dllState;
-    TrufflePkgInit.ContextStateImpl pkgInitState;
-    TruffleCall.ContextStateImpl callState;
-    TruffleStats.ContextStateImpl statsState;
+class TruffleLLVM_RFFIContextState implements ContextState {
+    TruffleLLVM_DLL.ContextStateImpl dllState;
+    TruffleLLVM_PkgInit.ContextStateImpl pkgInitState;
+    TruffleLLVM_Call.ContextStateImpl callState;
+    TruffleLLVM_Stats.ContextStateImpl statsState;
+    private final ContextState jniContextState;
 
-    TruffleRFFIContextState() {
-        dllState = TruffleDLL.newContextState();
-        pkgInitState = TrufflePkgInit.newContextState();
-        callState = TruffleCall.newContextState();
-        statsState = TruffleStats.newContextState();
+    TruffleLLVM_RFFIContextState(ContextState jniContextState) {
+        this.jniContextState = jniContextState;
+        dllState = TruffleLLVM_DLL.newContextState();
+        pkgInitState = TruffleLLVM_PkgInit.newContextState();
+        callState = TruffleLLVM_Call.newContextState();
+        statsState = TruffleLLVM_Stats.newContextState();
     }
 
-    static TruffleRFFIContextState getContextState() {
-        return (TruffleRFFIContextState) RContext.getInstance().getStateRFFI();
+    static TruffleLLVM_RFFIContextState getContextState() {
+        return (TruffleLLVM_RFFIContextState) RContext.getInstance().getStateRFFI();
     }
 
-    static TruffleRFFIContextState getContextState(RContext context) {
-        return (TruffleRFFIContextState) context.getStateRFFI();
+    static TruffleLLVM_RFFIContextState getContextState(RContext context) {
+        return (TruffleLLVM_RFFIContextState) context.getStateRFFI();
     }
 
     @Override
     public ContextState initialize(RContext context) {
+        jniContextState.initialize(context);
         dllState.initialize(context);
         pkgInitState.initialize(context);
         callState.initialize(context);
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/Truffle_RFFIFactory.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_RFFIFactory.java
similarity index 81%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/Truffle_RFFIFactory.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_RFFIFactory.java
index 8af33a15658061790ebdf5d51b566acb3fd62dd8..5a3324b95123c9149e5ed714018a3e5bc8e8416e 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/Truffle_RFFIFactory.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_RFFIFactory.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
@@ -35,16 +35,11 @@ import com.oracle.truffle.r.runtime.ffi.jni.JNI_RFFIFactory;
  * Incremental approach to using Truffle, defaults to the JNI factory.
  *
  */
-public class Truffle_RFFIFactory extends JNI_RFFIFactory implements RFFI {
-
-    @Override
-    protected void initialize(boolean runtime) {
-        super.initialize(runtime);
-    }
+public class TruffleLLVM_RFFIFactory extends JNI_RFFIFactory implements RFFI {
 
     @Override
     public ContextState newContextState() {
-        return new TruffleRFFIContextState();
+        return new TruffleLLVM_RFFIContextState(super.newContextState());
     }
 
     private CRFFI cRFFI;
@@ -52,7 +47,7 @@ public class Truffle_RFFIFactory extends JNI_RFFIFactory implements RFFI {
     @Override
     public CRFFI getCRFFI() {
         if (cRFFI == null) {
-            cRFFI = new TruffleC();
+            cRFFI = new TruffleLLVM_C();
         }
         return cRFFI;
     }
@@ -62,7 +57,7 @@ public class Truffle_RFFIFactory extends JNI_RFFIFactory implements RFFI {
     @Override
     public DLLRFFI getDLLRFFI() {
         if (dllRFFI == null) {
-            dllRFFI = new TruffleDLL();
+            dllRFFI = new TruffleLLVM_DLL();
         }
         return dllRFFI;
     }
@@ -72,7 +67,7 @@ public class Truffle_RFFIFactory extends JNI_RFFIFactory implements RFFI {
     @Override
     public UserRngRFFI getUserRngRFFI() {
         if (truffleUserRngRFFI == null) {
-            truffleUserRngRFFI = new TruffleUserRng();
+            truffleUserRngRFFI = new TruffleLLVM_UserRng();
         }
         return truffleUserRngRFFI;
     }
@@ -82,7 +77,7 @@ public class Truffle_RFFIFactory extends JNI_RFFIFactory implements RFFI {
     @Override
     public CallRFFI getCallRFFI() {
         if (truffleCallRFFI == null) {
-            truffleCallRFFI = new TruffleCall();
+            truffleCallRFFI = new TruffleLLVM_Call();
         }
         return truffleCallRFFI;
     }
@@ -91,11 +86,11 @@ public class Truffle_RFFIFactory extends JNI_RFFIFactory implements RFFI {
 
     @Override
     public StatsRFFI getStatsRFFI() {
-        if (TruffleDLL.isBlacklisted("stats")) {
+        if (TruffleLLVM_DLL.isBlacklisted("stats")) {
             return super.getStatsRFFI();
         }
         if (truffleStatsRFFI == null) {
-            truffleStatsRFFI = new TruffleStats();
+            truffleStatsRFFI = new TruffleLLVM_Stats();
         }
         return truffleStatsRFFI;
     }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleStats.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_Stats.java
similarity index 78%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleStats.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_Stats.java
index 431ff9d40ae71946343591c156a573a5154e17d0..b3e1d89e4f55eb714ccd5b0b8a7abb6e6f046bf8 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleStats.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_Stats.java
@@ -20,29 +20,29 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.engine.interop.NativeDoubleArray;
 import com.oracle.truffle.r.engine.interop.NativeIntegerArray;
-import com.oracle.truffle.r.engine.interop.ffi.TruffleStatsFactory.ExecuteFactorNodeGen;
-import com.oracle.truffle.r.engine.interop.ffi.TruffleStatsFactory.ExecuteWorkNodeGen;
+import com.oracle.truffle.r.engine.interop.ffi.llvm.TruffleLLVM_StatsFactory.ExecuteFactorNodeGen;
+import com.oracle.truffle.r.engine.interop.ffi.llvm.TruffleLLVM_StatsFactory.ExecuteWorkNodeGen;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
-import com.oracle.truffle.r.runtime.ffi.truffle.TruffleRFFIFrameHelper;
 
-public class TruffleStats implements StatsRFFI {
+public class TruffleLLVM_Stats implements StatsRFFI {
 
     public enum FFT_FUN {
         fft_work,
@@ -58,15 +58,15 @@ public class TruffleStats implements StatsRFFI {
              * it here.
              */
             if (context.getKind() == RContext.ContextKind.SHARE_PARENT_RW) {
-                TruffleDLL.ContextStateImpl contextState = TruffleRFFIContextState.getContextState().dllState;
-                TruffleDLL.ContextStateImpl parentDLLContextState = TruffleRFFIContextState.getContextState(context.getParent()).dllState;
-                TruffleDLL.ParseStatus parseStatus = null;
+                TruffleLLVM_DLL.ContextStateImpl contextState = TruffleLLVM_RFFIContextState.getContextState().dllState;
+                TruffleLLVM_DLL.ContextStateImpl parentDLLContextState = TruffleLLVM_RFFIContextState.getContextState(context.getParent()).dllState;
+                TruffleLLVM_DLL.ParseStatus parseStatus = null;
                 for (FFT_FUN f : FFT_FUN.values()) {
                     String funName = f.name();
-                    TruffleDLL.ParseStatus parentParseStatus = parentDLLContextState.parseStatusMap.get(funName);
+                    TruffleLLVM_DLL.ParseStatus parentParseStatus = parentDLLContextState.parseStatusMap.get(funName);
                     if (parentParseStatus != null) {
                         if (parseStatus == null) {
-                            parseStatus = new TruffleDLL.ParseStatus("stats", parentParseStatus.ir, false);
+                            parseStatus = new TruffleLLVM_DLL.ParseStatus("stats", parentParseStatus.ir, false);
                         }
                         contextState.parseStatusMap.put(f.name(), parseStatus);
                     }
@@ -85,14 +85,16 @@ public class TruffleStats implements StatsRFFI {
     }
 
     public abstract static class LookupAdapter extends Node {
+        @Child DLLRFFI.DLSymNode dllSymNode = RFFIFactory.getRFFI().getDLLRFFI().createDLSymNode();
+
         public SymbolHandle lookup(String name) {
             DLLInfo dllInfo = DLL.findLibrary("stats");
             // cannot go through DLL because stats does not allow dynamic lookup
             // and these symbols are not registered (only fft)
-            SymbolHandle result = TruffleDLL.getInstance().dlsym(dllInfo.handle, name);
+            SymbolHandle result = dllSymNode.execute(dllInfo.handle, name);
             if (result == DLL.SYMBOL_NOT_FOUND) {
                 @SuppressWarnings("unused")
-                TruffleRFFIContextState cs = TruffleRFFIContextState.getContextState();
+                TruffleLLVM_RFFIContextState cs = TruffleLLVM_RFFIContextState.getContextState();
                 throw RInternalError.shouldNotReachHere();
             }
             return result;
@@ -111,7 +113,7 @@ public class TruffleStats implements StatsRFFI {
             return doWork(a, nseg, n, nspn, isn, work, iwork, messageNode, fftWork);
         }
 
-        @Specialization(contains = "executeWorkCached")
+        @Specialization(replaces = "executeWorkCached")
         protected int executeWorkNormal(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork, @SuppressWarnings("unused") RContext context) {
             return doWork(a, nseg, n, nspn, isn, work, iwork, createMessageNode(), lookup("fft_work"));
         }
@@ -120,9 +122,8 @@ public class TruffleStats implements StatsRFFI {
             NativeDoubleArray na = new NativeDoubleArray(a);
             NativeDoubleArray nwork = new NativeDoubleArray(work);
             NativeIntegerArray niwork = new NativeIntegerArray(iwork);
-            VirtualFrame frame = TruffleRFFIFrameHelper.create();
             try {
-                return (int) ForeignAccess.sendExecute(messageNode, frame, fftWork.asTruffleObject(), na, nseg, n, nspn, isn, nwork, niwork);
+                return (int) ForeignAccess.sendExecute(messageNode, fftWork.asTruffleObject(), na, nseg, n, nspn, isn, nwork, niwork);
             } catch (Throwable t) {
                 throw RInternalError.shouldNotReachHere(t);
             }
@@ -153,7 +154,7 @@ public class TruffleStats implements StatsRFFI {
             doFactor(n, pmaxf, pmaxp, messageNode, fftFactor);
         }
 
-        @Specialization(contains = "executeFactorCached")
+        @Specialization(replaces = "executeFactorCached")
         protected void executeFactorNormal(int n, int[] pmaxf, int[] pmaxp, @SuppressWarnings("unused") RContext context) {
             doFactor(n, pmaxf, pmaxp, createMessageNode(), lookup("fft_factor"));
         }
@@ -161,10 +162,9 @@ public class TruffleStats implements StatsRFFI {
         private static void doFactor(int n, int[] pmaxf, int[] pmaxp, Node messageNode, SymbolHandle fftFactor) {
             NativeIntegerArray npmaxf = new NativeIntegerArray(pmaxf);
             NativeIntegerArray npmaxp = new NativeIntegerArray(pmaxp);
-            VirtualFrame frame = TruffleRFFIFrameHelper.create();
 
             try {
-                ForeignAccess.sendExecute(messageNode, frame, fftFactor.asTruffleObject(), n, npmaxf, npmaxp);
+                ForeignAccess.sendExecute(messageNode, fftFactor.asTruffleObject(), n, npmaxf, npmaxp);
             } catch (Throwable t) {
                 throw RInternalError.shouldNotReachHere(t);
             }
@@ -183,23 +183,31 @@ public class TruffleStats implements StatsRFFI {
         }
     }
 
-    public static class Truffle_FFTNode extends FFTNode {
-        @Child ExecuteWork executeWork = ExecuteWork.create();
+    public static class Truffle_FactorNode extends FactorNode {
         @Child ExecuteFactor executeFactor = ExecuteFactor.create();
 
         @Override
-        public int executeWork(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
-            return executeWork.execute(a, nseg, n, nspn, isn, work, iwork, RContext.getInstance());
+        public void execute(int n, int[] pmaxf, int[] pmaxp) {
+            executeFactor.execute(n, pmaxf, pmaxp, RContext.getInstance());
         }
+    }
+
+    public static class Truffle_WorkNode extends WorkNode {
+        @Child ExecuteWork executeWork = ExecuteWork.create();
 
         @Override
-        public void executeFactor(int n, int[] pmaxf, int[] pmaxp) {
-            executeFactor.execute(n, pmaxf, pmaxp, RContext.getInstance());
+        public int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
+            return executeWork.execute(a, nseg, n, nspn, isn, work, iwork, RContext.getInstance());
         }
     }
 
     @Override
-    public FFTNode createFFTNode() {
-        return new Truffle_FFTNode();
+    public FactorNode createFactorNode() {
+        return new Truffle_FactorNode();
+    }
+
+    @Override
+    public WorkNode createWorkNode() {
+        return new Truffle_WorkNode();
     }
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCallHelper.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java
similarity index 51%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCallHelper.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java
index 420b4218e7b55c868b73c880a4fd5a45476be0e4..bf5eeed417c045b2d985d2659a550f544863abca 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCallHelper.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UpCallsRFFIImpl.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
 import java.nio.charset.StandardCharsets;
 
@@ -31,6 +31,8 @@ import com.oracle.truffle.r.engine.interop.NativeDoubleArray;
 import com.oracle.truffle.r.engine.interop.NativeIntegerArray;
 import com.oracle.truffle.r.engine.interop.NativeLogicalArray;
 import com.oracle.truffle.r.engine.interop.NativeRawArray;
+import com.oracle.truffle.r.nodes.ffi.RFFIUtils;
+import com.oracle.truffle.r.nodes.ffi.JavaUpCallsRFFIImpl;
 import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -42,40 +44,42 @@ import com.oracle.truffle.r.runtime.data.RScalar;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.RUnboundValue;
 import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
-import com.oracle.truffle.r.runtime.ffi.JavaUpCallsRFFI;
+import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
+import com.oracle.truffle.r.runtime.ffi.jni.JNIUpCallsRFFIImpl;
 
 /**
- * A wrapper class that can be instantiated and export for method lookup. For now just delegates to
- * {@link JavaUpCallsRFFI}.
+ * (Incomplete) Variant of {@link JavaUpCallsRFFIImpl} for Truffle LLVM.
  *
  */
-public class TruffleCallHelper extends JavaUpCallsRFFI {
-    private static TruffleCallHelper singleton;
+public class TruffleLLVM_UpCallsRFFIImpl extends JNIUpCallsRFFIImpl implements VariableUpCallsRFFI {
+    private static TruffleLLVM_UpCallsRFFIImpl singleton;
     private static TruffleObject singletonTruffleObject;
 
     public static TruffleObject initialize() {
         if (singleton == null) {
-            singleton = new TruffleCallHelper();
+            singleton = new TruffleLLVM_UpCallsRFFIImpl();
             singletonTruffleObject = JavaInterop.asTruffleObject(singleton);
         }
         return singletonTruffleObject;
     }
 
     public Object charSXPToNativeCharArray(Object x) {
-        CharSXPWrapper chars = guaranteeInstanceOf(x, CharSXPWrapper.class);
+        CharSXPWrapper chars = RFFIUtils.guaranteeInstanceOf(x, CharSXPWrapper.class);
         return new NativeCharArray(chars.getContents().getBytes());
     }
 
     // Checkstyle: stop method name check
 
-    public Object Rf_mkCharLenCE(Object bytes, int encoding) {
+    @Override
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
         if (bytes instanceof NativeCharArray) {
-            return super.Rf_mkCharLenCE(((NativeCharArray) bytes).getBytes(), encoding);
+            return super.Rf_mkCharLenCE(((NativeCharArray) bytes).getBytes(), len, encoding);
         } else {
             throw RInternalError.unimplemented();
         }
     }
 
+    @Override
     public Object Rf_install(Object name) {
         if (name instanceof NativeCharArray) {
             return RDataFactory.createSymbolInterned(new String(((NativeCharArray) name).getBytes(), StandardCharsets.UTF_8));
@@ -124,14 +128,6 @@ public class TruffleCallHelper extends JavaUpCallsRFFI {
         }
     }
 
-    public Object R_NilValue() {
-        return RNull.instance;
-    }
-
-    public Object R_UnboundValue() {
-        return RUnboundValue.instance;
-    }
-
     public Object bytesToNativeCharArray(byte[] bytes) {
         return new NativeCharArray(bytes);
     }
@@ -147,4 +143,180 @@ public class TruffleCallHelper extends JavaUpCallsRFFI {
             throw RInternalError.shouldNotReachHere();
         }
     }
+
+    @Override
+    public Object R_NilValue() {
+        return RNull.instance;
+    }
+
+    @Override
+    public Object R_UnboundValue() {
+        return RUnboundValue.instance;
+    }
+
+    @Override
+    public Object R_Srcref() {
+        return RFFIVariables.R_Srcref.getValue();
+    }
+
+    @Override
+    public Object R_MissingArg() {
+        return RFFIVariables.R_MissingArg.getValue();
+    }
+
+    @Override
+    public Object R_BaseSymbol() {
+        return RFFIVariables.R_BaseSymbol.getValue();
+    }
+
+    @Override
+    public Object R_BraceSymbol() {
+        return RFFIVariables.R_BraceSymbol.getValue();
+    }
+
+    @Override
+    public Object R_Bracket2Symbol() {
+        return RFFIVariables.R_Bracket2Symbol.getValue();
+    }
+
+    @Override
+    public Object R_BracketSymbol() {
+        return RFFIVariables.R_BracketSymbol.getValue();
+    }
+
+    @Override
+    public Object R_ClassSymbol() {
+        return RFFIVariables.R_ClassSymbol.getValue();
+    }
+
+    @Override
+    public Object R_DeviceSymbol() {
+        return RFFIVariables.R_DeviceSymbol.getValue();
+    }
+
+    @Override
+    public Object R_DimNamesSymbol() {
+        return RFFIVariables.R_DimNamesSymbol.getValue();
+    }
+
+    @Override
+    public Object R_DimSymbol() {
+        return RFFIVariables.R_DimSymbol.getValue();
+    }
+
+    @Override
+    public Object R_DollarSymbol() {
+        return RFFIVariables.R_DollarSymbol.getValue();
+    }
+
+    @Override
+    public Object R_DotsSymbol() {
+        return RFFIVariables.R_DotsSymbol.getValue();
+    }
+
+    @Override
+    public Object R_DropSymbol() {
+        return RFFIVariables.R_DropSymbol.getValue();
+    }
+
+    @Override
+    public Object R_LastvalueSymbol() {
+        return RFFIVariables.R_LastvalueSymbol.getValue();
+    }
+
+    @Override
+    public Object R_LevelsSymbol() {
+        return RFFIVariables.R_LevelsSymbol.getValue();
+    }
+
+    @Override
+    public Object R_ModeSymbol() {
+        return RFFIVariables.R_ModeSymbol.getValue();
+    }
+
+    @Override
+    public Object R_NaRmSymbol() {
+        return RFFIVariables.R_NaRmSymbol.getValue();
+    }
+
+    @Override
+    public Object R_NameSymbol() {
+        return RFFIVariables.R_NameSymbol.getValue();
+    }
+
+    @Override
+    public Object R_NamesSymbol() {
+        return RFFIVariables.R_NamesSymbol.getValue();
+    }
+
+    @Override
+    public Object R_NamespaceEnvSymbol() {
+        return RFFIVariables.R_NamespaceEnvSymbol.getValue();
+    }
+
+    @Override
+    public Object R_PackageSymbol() {
+        return RFFIVariables.R_PackageSymbol.getValue();
+    }
+
+    @Override
+    public Object R_QuoteSymbol() {
+        return RFFIVariables.R_QuoteSymbol.getValue();
+    }
+
+    @Override
+    public Object R_RowNamesSymbol() {
+        return RFFIVariables.R_RowNamesSymbol.getValue();
+    }
+
+    @Override
+    public Object R_SeedsSymbol() {
+        return RFFIVariables.R_SeedsSymbol.getValue();
+    }
+
+    @Override
+    public Object R_SourceSymbol() {
+        return RFFIVariables.R_SourceSymbol.getValue();
+    }
+
+    @Override
+    public Object R_TspSymbol() {
+        return RFFIVariables.R_TspSymbol.getValue();
+    }
+
+    @Override
+    public Object R_dot_defined() {
+        return RFFIVariables.R_dot_defined.getValue();
+    }
+
+    @Override
+    public Object R_dot_Method() {
+        return RFFIVariables.R_dot_Method.getValue();
+    }
+
+    @Override
+    public Object R_dot_target() {
+        return RFFIVariables.R_dot_target.getValue();
+    }
+
+    @Override
+    public Object R_NaString() {
+        return RFFIVariables.R_NaString.getValue();
+    }
+
+    @Override
+    public Object R_BlankString() {
+        return RFFIVariables.R_BlankString.getValue();
+    }
+
+    @Override
+    public Object R_BlankScalarString() {
+        return RFFIVariables.R_BlankScalarString.getValue();
+    }
+
+    @Override
+    public Object R_EmptyEnv() {
+        return RFFIVariables.R_EmptyEnv.getValue();
+    }
+
 }
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleUserRng.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UserRng.java
similarity index 75%
rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleUserRng.java
rename to com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UserRng.java
index 41c8dacbd0c378c4b2380f127d4e9deab08d10e6..74dbb58f09a6dee2952996225d2e94c439f6fd15 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleUserRng.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/TruffleLLVM_UserRng.java
@@ -20,18 +20,16 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.engine.interop.ffi;
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
 
-import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.Message;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.UserRngRFFI;
-import com.oracle.truffle.r.runtime.ffi.truffle.TruffleRFFIFrameHelper;
 import com.oracle.truffle.r.runtime.rng.user.UserRNG.Function;
 
-public class TruffleUserRng implements UserRngRFFI {
+public class TruffleLLVM_UserRng implements UserRngRFFI {
     private static class TruffleUserRngRFFINode extends UserRngRFFINode {
         Node initMessage;
         Node randMessage;
@@ -41,12 +39,11 @@ public class TruffleUserRng implements UserRngRFFI {
 
         @Override
         public void init(int seed) {
-            VirtualFrame frame = TruffleRFFIFrameHelper.create();
             if (initMessage == null) {
                 initMessage = Message.createExecute(1).createNode();
             }
             try {
-                ForeignAccess.sendExecute(initMessage, frame, Function.Init.getSymbolHandle().asTruffleObject(), seed);
+                ForeignAccess.sendExecute(initMessage, Function.Init.getSymbolHandle().asTruffleObject(), seed);
             } catch (Throwable t) {
                 throw RInternalError.shouldNotReachHere();
             }
@@ -54,13 +51,12 @@ public class TruffleUserRng implements UserRngRFFI {
 
         @Override
         public double rand() {
-            VirtualFrame frame = TruffleRFFIFrameHelper.create();
             if (randMessage == null) {
                 randMessage = Message.createExecute(0).createNode();
             }
             try {
-                Object address = ForeignAccess.sendExecute(randMessage, frame, Function.Rand.getSymbolHandle().asTruffleObject());
-                Object value = ForeignAccess.sendExecute(readPointerNode, frame, TruffleCAccess.Function.READ_POINTER_DOUBLE.getSymbolHandle().asTruffleObject(), address);
+                Object address = ForeignAccess.sendExecute(randMessage, Function.Rand.getSymbolHandle().asTruffleObject());
+                Object value = ForeignAccess.sendExecute(readPointerNode, TruffleLLVM_CAccess.Function.READ_POINTER_DOUBLE.getSymbolHandle().asTruffleObject(), address);
                 return (double) value;
             } catch (Throwable t) {
                 throw RInternalError.shouldNotReachHere();
@@ -69,13 +65,12 @@ public class TruffleUserRng implements UserRngRFFI {
 
         @Override
         public int nSeed() {
-            VirtualFrame frame = TruffleRFFIFrameHelper.create();
             if (nSeedMessage == null) {
                 nSeedMessage = Message.createExecute(0).createNode();
             }
             try {
-                Object address = ForeignAccess.sendExecute(nSeedMessage, frame, Function.NSeed.getSymbolHandle().asTruffleObject());
-                Object n = ForeignAccess.sendExecute(readPointerNode, frame, TruffleCAccess.Function.READ_POINTER_INT.getSymbolHandle().asTruffleObject(), address);
+                Object address = ForeignAccess.sendExecute(nSeedMessage, Function.NSeed.getSymbolHandle().asTruffleObject());
+                Object n = ForeignAccess.sendExecute(readPointerNode, TruffleLLVM_CAccess.Function.READ_POINTER_INT.getSymbolHandle().asTruffleObject(), address);
                 return (int) n;
             } catch (Throwable t) {
                 throw RInternalError.shouldNotReachHere();
@@ -84,14 +79,13 @@ public class TruffleUserRng implements UserRngRFFI {
 
         @Override
         public void seeds(int[] n) {
-            VirtualFrame frame = TruffleRFFIFrameHelper.create();
             if (seedsMessage == null) {
                 seedsMessage = Message.createExecute(0).createNode();
             }
             try {
-                Object address = ForeignAccess.sendExecute(seedsMessage, frame, Function.Seedloc.getSymbolHandle().asTruffleObject());
+                Object address = ForeignAccess.sendExecute(seedsMessage, Function.Seedloc.getSymbolHandle().asTruffleObject());
                 for (int i = 0; i < n.length; i++) {
-                    Object seed = ForeignAccess.sendExecute(readPointerNode, frame, TruffleCAccess.Function.READ_ARRAY_INT.getSymbolHandle().asTruffleObject(), address, i);
+                    Object seed = ForeignAccess.sendExecute(readPointerNode, TruffleLLVM_CAccess.Function.READ_ARRAY_INT.getSymbolHandle().asTruffleObject(), address, i);
                     n[i] = (int) seed;
                 }
             } catch (Throwable t) {
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/VariableUpCallsRFFI.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/VariableUpCallsRFFI.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1749e8e99b73274a59308a74f546a8a9310f371
--- /dev/null
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/llvm/VariableUpCallsRFFI.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.engine.interop.ffi.llvm;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+
+/**
+ * This exists because {@link TruffleObject} instances cannot currently be stored in memory, so
+ * upcall to get the values.
+ *
+ * TODO Some of these, e.g. {@link #R_NilValue}, are performance sensitive, but most are not. So we
+ * could collapse those into a single upcall that returned all the values in one go and extract the
+ * value with another upcall.
+ */
+public interface VariableUpCallsRFFI {
+    // Checkstyle: stop method name check
+
+    Object R_EmptyEnv();
+
+    Object R_NilValue();
+
+    Object R_UnboundValue();
+
+    Object R_Srcref();
+
+    Object R_MissingArg();
+
+    Object R_BaseSymbol();
+
+    Object R_BraceSymbol();
+
+    Object R_Bracket2Symbol();
+
+    Object R_BracketSymbol();
+
+    Object R_ClassSymbol();
+
+    Object R_DeviceSymbol();
+
+    Object R_DimNamesSymbol();
+
+    Object R_DimSymbol();
+
+    Object R_DollarSymbol();
+
+    Object R_DotsSymbol();
+
+    Object R_DropSymbol();
+
+    Object R_LastvalueSymbol();
+
+    Object R_LevelsSymbol();
+
+    Object R_ModeSymbol();
+
+    Object R_NaRmSymbol();
+
+    Object R_NameSymbol();
+
+    Object R_NamesSymbol();
+
+    Object R_NamespaceEnvSymbol();
+
+    Object R_PackageSymbol();
+
+    Object R_QuoteSymbol();
+
+    Object R_RowNamesSymbol();
+
+    Object R_SeedsSymbol();
+
+    Object R_SourceSymbol();
+
+    Object R_TspSymbol();
+
+    Object R_dot_defined();
+
+    Object R_dot_Method();
+
+    Object R_dot_target();
+
+    Object R_NaString();
+
+    Object R_BlankString();
+
+    Object R_BlankScalarString();
+
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java
index 80db131f722d551a68699d9929bd1301efce1fe4..539994d1f72cc6389624c2d03b341aaf0d206a1f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grDevices/DevicesCCalls.java
@@ -8,44 +8,74 @@
  * Copyright (c) 1998--2014, The R Core Team
  * Copyright (c) 2002--2010, The R Foundation
  * Copyright (C) 2005--2006, Morten Welinder
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
 package com.oracle.truffle.r.library.grDevices;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyStringVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
+
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.library.grDevices.DevicesCCallsFactory.C_DevOffNodeGen;
 import com.oracle.truffle.r.library.grDevices.pdf.PdfGraphicsDevice;
 import com.oracle.truffle.r.library.graphics.core.GraphicsEngineImpl;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public class DevicesCCalls {
-    public static final class C_DevOff extends RExternalBuiltinNode {
+    public abstract static class C_DevOff extends RExternalBuiltinNode.Arg1 {
+        public static C_DevOff create() {
+            return C_DevOffNodeGen.create();
+        }
 
-        @Override
-        @TruffleBoundary
-        public Object call(RArgsValuesAndNames args) {
-            Object firstArgument = args.getArgument(0);
-            int deviceIndex = castInt(castVector(firstArgument));
+        static {
+            Casts casts = new Casts(C_DevOff.class);
+            casts.arg(0).asIntegerVector().findFirst();
+        }
+
+        @Specialization
+        public Object doCall(int deviceIndex) {
             GraphicsEngineImpl.getInstance().killGraphicsDeviceByIndex(deviceIndex);
             return RNull.instance;
         }
     }
 
-    public static final class C_DevCur extends RExternalBuiltinNode {
+    public static final class C_DevCur extends RExternalBuiltinNode.Arg0 {
 
         @Override
         @TruffleBoundary
-        public Object call(RArgsValuesAndNames args) {
+        public Object execute() {
             return GraphicsEngineImpl.getInstance().getCurrentGraphicsDeviceIndex();
         }
     }
 
     public static final class C_PDF extends RExternalBuiltinNode {
 
+        @Child private CastNode extractFontsNode;
+        @Child private CastNode asStringNode;
+        @Child private CastNode asDoubleNode;
+        @Child private CastNode asLogicalNode;
+        @Child private CastNode asIntNode;
+
+        static {
+            Casts.noCasts(C_PDF.class);
+        }
+
+        public C_PDF() {
+            asStringNode = newCastBuilder().asStringVector().findFirst().buildCastNode();
+            asDoubleNode = newCastBuilder().asDoubleVector().findFirst().buildCastNode();
+            asLogicalNode = newCastBuilder().asLogicalVector().findFirst().buildCastNode();
+            asIntNode = newCastBuilder().asIntegerVector().findFirst().buildCastNode();
+            extractFontsNode = newCastBuilder().mapNull(emptyStringVector()).mustBe(stringValue()).asStringVector().buildCastNode();
+        }
+
         @SuppressWarnings("unused")
         @Override
         @TruffleBoundary
@@ -57,33 +87,48 @@ public class DevicesCCalls {
 
         private PdfGraphicsDevice.Parameters extractParametersFrom(RArgsValuesAndNames args) {
             PdfGraphicsDevice.Parameters result = new PdfGraphicsDevice.Parameters();
-            result.filePath = isString(args.getArgument(0));
-            result.paperSize = isString(args.getArgument(1));
-            result.fontFamily = isString(args.getArgument(2));
-            result.encoding = isString(args.getArgument(3));
-            result.bg = isString(args.getArgument(4));
-            result.fg = isString(args.getArgument(5));
-            result.width = castDouble(castVector(args.getArgument(6))).getDataAt(0);
-            result.height = castDouble(castVector(args.getArgument(7))).getDataAt(0);
-            result.pointSize = castDouble(castVector(args.getArgument(8))).getDataAt(0);
-            result.oneFile = castLogical(castVector(args.getArgument(9)));
-            result.pageCenter = castLogical(castVector(args.getArgument(10)));
-            result.title = isString(args.getArgument(11));
+            result.filePath = asString(args.getArgument(0));
+            result.paperSize = asString(args.getArgument(1));
+            result.fontFamily = asString(args.getArgument(2));
+            result.encoding = asString(args.getArgument(3));
+            result.bg = asString(args.getArgument(4));
+            result.fg = asString(args.getArgument(5));
+            result.width = asDouble(castVector(args.getArgument(6)));
+            result.height = asDouble(castVector(args.getArgument(7)));
+            result.pointSize = asDouble(castVector(args.getArgument(8)));
+            result.oneFile = asLogical(castVector(args.getArgument(9)));
+            result.pageCenter = asLogical(castVector(args.getArgument(10)));
+            result.title = asString(args.getArgument(11));
             result.fonts = extractFontsFrom(args.getArgument(12));
 
-            result.majorVersion = castInt(castVector(args.getArgument(13)));
-            result.minorVersion = castInt(castVector(args.getArgument(14)));
-            result.colormodel = isString(args.getArgument(15));
-            result.useDingbats = castLogical(castVector(args.getArgument(16)));
-            result.useKerning = castLogical(castVector(args.getArgument(17)));
-            result.fillOddEven = castLogical(castVector(args.getArgument(18)));
-            result.compress = castLogical(castVector(args.getArgument(19)));
+            result.majorVersion = asInt(castVector(args.getArgument(13)));
+            result.minorVersion = asInt(castVector(args.getArgument(14)));
+            result.colormodel = asString(args.getArgument(15));
+            result.useDingbats = asLogical(castVector(args.getArgument(16)));
+            result.useKerning = asLogical(castVector(args.getArgument(17)));
+            result.fillOddEven = asLogical(castVector(args.getArgument(18)));
+            result.compress = asLogical(castVector(args.getArgument(19)));
             return result;
         }
 
-        @SuppressWarnings("static-method")
+        private String asString(Object value) {
+            return (String) asStringNode.execute(value);
+        }
+
+        private int asInt(Object value) {
+            return (Integer) asIntNode.execute(value);
+        }
+
+        private double asDouble(Object value) {
+            return (Double) asDoubleNode.execute(value);
+        }
+
+        private byte asLogical(Object value) {
+            return (Byte) asLogicalNode.execute(value);
+        }
+
         private String[] extractFontsFrom(Object inputArgument) {
-            return inputArgument == RNull.instance ? new String[0] : ((RStringVector) inputArgument).getDataCopy();
+            return ((RAbstractStringVector) extractFontsNode.execute(inputArgument)).materialize().getDataCopy();
         }
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java
index b2a33bdf8dd8156ff369c6f382bbc64d8507f3de..695ba86dbbfa3af1761cecfaba525de6ed53f736 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/graphics/GraphicsCCalls.java
@@ -8,12 +8,16 @@
  * Copyright (c) 1998--2014, The R Core Team
  * Copyright (c) 2002--2010, The R Foundation
  * Copyright (C) 2005--2006, Morten Welinder
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
 package com.oracle.truffle.r.library.graphics;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
+
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.library.graphics.core.DrawingParameters;
 import com.oracle.truffle.r.library.graphics.core.GraphicsDevice;
@@ -22,21 +26,29 @@ import com.oracle.truffle.r.library.graphics.core.GraphicsEngineImpl;
 import com.oracle.truffle.r.library.graphics.core.geometry.Coordinates;
 import com.oracle.truffle.r.library.graphics.core.geometry.CoordinatesFactory;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 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;
 
 public class GraphicsCCalls {
     public static final class C_PlotXY extends RExternalBuiltinNode {
+        @Child private CastNode castXYNode;
+
+        static {
+            Casts.noCasts(C_PlotXY.class);
+        }
+
+        public C_PlotXY() {
+            castXYNode = newCastBuilder().mustBe(doubleValue().and(size(2))).asDoubleVector().buildCastNode();
+        }
 
         @Override
         @TruffleBoundary
         public RNull call(RArgsValuesAndNames args) {
-            RDoubleVector xyVector = ((RAbstractDoubleVector) args.getArgument(0)).materialize();
-            assert xyVector.getLength() % 2 == 0 : "wrong size of vector";
+            RDoubleVector xyVector = (RDoubleVector) castXYNode.execute(args.getArgument(0));
             getGraphicsEngine().setCurrentGraphicsDeviceMode(GraphicsDevice.Mode.GRAPHICS_ON);
             drawWithLines(xyVector);
             return RNull.instance;
@@ -71,6 +83,10 @@ public class GraphicsCCalls {
 
     public static final class C_Par extends RExternalBuiltinNode {
 
+        static {
+            Casts.noCasts(C_Par.class);
+        }
+
         @Override
         @TruffleBoundary
         public Object call(RArgsValuesAndNames args) {
@@ -91,6 +107,15 @@ public class GraphicsCCalls {
         private double cex = RRuntime.DOUBLE_NA;
         private double col = RRuntime.DOUBLE_NA;
         private double font = RRuntime.DOUBLE_NA;
+        @Child private CastNode firstDoubleCast;
+
+        static {
+            Casts.noCasts(C_mtext.class);
+        }
+
+        public C_mtext() {
+            firstDoubleCast = newCastBuilder().asDoubleVector().findFirst().buildCastNode();
+        }
 
         @Override
         @TruffleBoundary
@@ -113,7 +138,7 @@ public class GraphicsCCalls {
         }
 
         private double extractFirstDoubleValueFrom(Object arg) {
-            return castDouble(castVector(arg)).getDataAt(0);
+            return (Double) firstDoubleCast.execute(arg);
         }
     }
 }
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 72fe424293cbb87439f36e62ac18a963e59595d0..11c4a71ce6b38c8afb385a9a5be2670ce5a16a14 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
@@ -8,7 +8,7 @@
  * Copyright (c) 1998--2014, The R Core Team
  * Copyright (c) 2002--2010, The R Foundation
  * Copyright (C) 2005--2006, Morten Welinder
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.FFIRootNode;
+import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 
 /**
@@ -61,10 +61,10 @@ public class RGraphics {
                 baseEnv.safePut(DOT_DEVICES, devices);
                 registerBaseGraphicsSystem();
             } else {
-                DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
-                DLL.SymbolHandle func = DLL.findSymbol("InitGraphics", null, rns);
-                assert func != DLL.SYMBOL_NOT_FOUND;
-                FFIRootNode.createCallTarget().call(new NativeCallInfo("InitGraphics", func, DLL.findLibrary("graphics")), true, new Object[0]);
+                DLL.DLLInfo dllInfo = DLL.findLibrary("graphics");
+                DLL.SymbolHandle symbolHandle = DLL.findSymbol("InitGraphics", dllInfo);
+                assert symbolHandle != DLL.SYMBOL_NOT_FOUND;
+                CallRFFI.InvokeVoidCallRootNode.create().getCallTarget().call(new NativeCallInfo("InitGraphics", symbolHandle, dllInfo), 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 b5bca848f34ad5a305ef9ecc3213e0d1a1d5ad85..6623a2c7ca6a8538ce7bbe35792f2b8f5c18294e 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
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -35,12 +34,12 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 public class GridFunctions {
 
     public abstract static class InitGrid extends RExternalBuiltinNode.Arg1 {
-        @Child GridRFFI.GridRFFINode gridRFFINode = RFFIFactory.getRFFI().getGridRFFI().createGridRFFINode();
+        @Child GridRFFI.InitGridNode initGridNode = RFFIFactory.getRFFI().getGridRFFI().createInitGridNode();
 
         @Specialization
         @TruffleBoundary
         protected Object initGrid(REnvironment gridEvalEnv) {
-            return gridRFFINode.initGrid(gridEvalEnv);
+            return initGridNode.execute(gridEvalEnv);
         }
 
         @Fallback
@@ -50,18 +49,23 @@ public class GridFunctions {
     }
 
     public static final class KillGrid extends RExternalBuiltinNode {
-        @Child GridRFFI.GridRFFINode gridRFFINode = RFFIFactory.getRFFI().getGridRFFI().createGridRFFINode();
+        @Child GridRFFI.KillGridNode killGridNode = RFFIFactory.getRFFI().getGridRFFI().createKillGridNode();
+
+        static {
+            Casts.noCasts(KillGrid.class);
+        }
 
         @Override
         @TruffleBoundary
         public Object call(RArgsValuesAndNames args) {
-            return gridRFFINode.killGrid();
+            return killGridNode.execute();
         }
     }
 
     public abstract static class ValidUnits extends RExternalBuiltinNode.Arg1 {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ValidUnits.class);
             casts.arg(0).mustBe(stringValue(), RError.Message.GENERIC, "'units' must be character").asStringVector().mustBe(notEmpty(), RError.Message.GENERIC, "'units' must be of length > 0");
         }
 
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 cf78e10d6a1483ac8f996b28d2314c7eed12a42a..48f6249fe47be0de70c34485090586d4674ca342 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
@@ -13,6 +13,7 @@ package com.oracle.truffle.r.library.methods;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lengthGt;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lengthGte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
@@ -32,7 +33,7 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNodeGen;
@@ -55,7 +56,6 @@ import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
@@ -68,8 +68,25 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 public class MethodsListDispatch {
 
+    private static void checkSingleString(Casts casts, int argNum, String argName, String msg, boolean nonEmpty, Function<Object, String> clsHierFn,
+                    Function<Object, Integer> vecLenFn) {
+        //@formatter:off
+        casts.arg(argNum, argName).
+            defaultError(RError.NO_CALLER, RError.Message.SINGLE_STRING_WRONG_TYPE, msg, clsHierFn).
+            mustBe(stringValue()).
+            asStringVector().
+            mustBe(singleElement(), RError.NO_CALLER, RError.Message.SINGLE_STRING_TOO_LONG, msg, vecLenFn).
+            findFirst().
+            mustBe(nonEmpty ? lengthGt(0) : lengthGte(0), RError.NO_CALLER, RError.Message.NON_EMPTY_STRING, msg);
+        //@formatter:on
+    }
+
     public abstract static class R_initMethodDispatch extends RExternalBuiltinNode.Arg1 {
 
+        static {
+            Casts.noCasts(R_initMethodDispatch.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected REnvironment initMethodDispatch(REnvironment env) {
@@ -87,34 +104,34 @@ public class MethodsListDispatch {
 
     public abstract static class R_methodsPackageMetaName extends RExternalBuiltinNode.Arg3 {
 
+        static {
+            Casts casts = new Casts(R_methodsPackageMetaName.class);
+            Function<Object, String> clsHierFn = ClassHierarchyScalarNode::get;
+            Function<Object, Integer> vecLenFn = arg -> ((RAbstractStringVector) arg).getLength();
+
+            checkSingleString(casts, 0, "prefix", "The internal prefix (e.g., \"C\") for a meta-data object", true, clsHierFn, vecLenFn);
+            checkSingleString(casts, 1, "name", "The name of the object (e.g,. a class or generic function) to find in the meta-data", false, clsHierFn, vecLenFn);
+            checkSingleString(casts, 2, "pkg", "The name of the package for a meta-data object", false, clsHierFn, vecLenFn);
+        }
+
         @Specialization
         @TruffleBoundary
-        protected String callMethodsPackageMetaName(RAbstractStringVector prefixStringVector, RAbstractStringVector nameStringVector, RAbstractStringVector pkgStringVector) {
-            // TODO: proper error messages
-            assert prefixStringVector.getLength() == 1 && nameStringVector.getLength() == 1 && pkgStringVector.getLength() == 1;
-            String prefixString = prefixStringVector.getDataAt(0);
-            String nameString = nameStringVector.getDataAt(0);
-            String pkgString = pkgStringVector.getDataAt(0);
-
-            if (pkgString.length() == 0) {
-                return ".__" + prefixString + "__" + nameString;
+        protected String callMethodsPackageMetaName(String prefix, String name, String pkg) {
+            if (pkg.length() == 0) {
+                return ".__" + prefix + "__" + name;
             } else {
-                return ".__" + prefixString + "__" + nameString + ":" + pkgString;
+                return ".__" + prefix + "__" + name + ":" + pkg;
             }
         }
     }
 
     public abstract static class R_getClassFromCache extends RExternalBuiltinNode.Arg2 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg(0, "klass").defaultError(RError.Message.GENERIC, "class should be either a character-string name or a class definition").
-                mustNotBeNull().
-                mustBe(stringValue().or(instanceOf(RS4Object.class)));
+        static {
+            Casts casts = new Casts(R_getClassFromCache.class);
+            casts.arg(0, "klass").defaultError(RError.Message.GENERIC, "class should be either a character-string name or a class definition").mustBe(stringValue().or(instanceOf(RS4Object.class)));
 
             casts.arg(1, "table").mustNotBeNull(RError.NO_CALLER, RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
-            //@formatter:on
         }
 
         protected GetFixedAttributeNode createPckgAttrAccess() {
@@ -160,8 +177,8 @@ public class MethodsListDispatch {
 
     public abstract static class R_set_method_dispatch extends RExternalBuiltinNode.Arg1 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R_set_method_dispatch.class);
             casts.arg(0).asLogicalVector().findFirst(RRuntime.LOGICAL_NA);
         }
 
@@ -185,21 +202,26 @@ public class MethodsListDispatch {
     public abstract static class R_M_setPrimitiveMethods extends RExternalBuiltinNode.Arg5 {
         @Child private AccessSlotNode accessSlotNode;
 
+        static {
+            Casts casts = new Casts(R_M_setPrimitiveMethods.class);
+            casts.arg(0, "fname").asStringVector().findFirst();
+            casts.arg(1, "op");
+            casts.arg(2, "code").mustBe(stringValue()).asStringVector().findFirst();
+            casts.arg(3, "fundef");
+            casts.arg(4, "mlist");
+        }
+
         private AccessSlotNode initAccessSlotNode() {
             if (accessSlotNode == null) {
-                accessSlotNode = insert(AccessSlotNodeGen.create(true, null, null));
+                accessSlotNode = insert(AccessSlotNodeGen.create(true));
             }
             return accessSlotNode;
         }
 
         @Specialization
         @TruffleBoundary
-        protected Object setPrimitiveMethods(Object fname, Object op, Object codeVec, RTypedValue fundef, Object mlist) {
-            String fnameString = RRuntime.asString(fname);
-            String codeVecString = RRuntime.asString(codeVec);
-            if (codeVecString == null) {
-                throw RError.error(this, RError.Message.GENERIC, "argument 'code' must be a character string");
-            }
+        protected Object setPrimitiveMethods(String fnameString, Object op, String codeVecString, Object fundefObj, Object mlist) {
+            RTypedValue fundef = (RTypedValue) fundefObj;
 
             if (op == RNull.instance) {
                 byte value = RRuntime.asLogical(RContext.getInstance().allowPrimitiveMethods());
@@ -274,6 +296,10 @@ public class MethodsListDispatch {
 
     public abstract static class R_identC extends RExternalBuiltinNode.Arg2 {
 
+        static {
+            Casts.noCasts(R_identC.class);
+        }
+
         @Specialization
         protected Object identC(RAbstractStringVector e1, RAbstractStringVector e2) {
             if (e1.getLength() == 1 && e2.getLength() == 1 && e1.getDataAt(0).equals(e2.getDataAt(0))) {
@@ -294,41 +320,18 @@ public class MethodsListDispatch {
 
         @Child private GetGenericInternal getGenericInternal = GetGenericInternalNodeGen.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R_getGeneric.class);
             Function<Object, String> clsHierFn = ClassHierarchyScalarNode::get;
-
-            //@formatter:off
             Function<Object, Integer> vecLenFn = arg -> ((RAbstractStringVector) arg).getLength();
 
-            String msg0 = "The argument \"f\" to getGeneric";
-            casts.arg(0, "f").
-                defaultError(RError.NO_CALLER, RError.Message.SINGLE_STRING_WRONG_TYPE, msg0, clsHierFn).
-                mustNotBeNull().
-                mustBe(stringValue()).
-                asStringVector().
-                mustBe(singleElement(), RError.NO_CALLER, RError.Message.SINGLE_STRING_TOO_LONG, msg0, vecLenFn).
-                findFirst().
-                mustBe(lengthGt(0), RError.NO_CALLER, RError.Message.NON_EMPTY_STRING, msg0);
-
-            casts.arg(1, "mustFind").
-                asLogicalVector().
-                findFirst(RRuntime.LOGICAL_NA).
-                map(toBoolean());
-
-            casts.arg(2, "env").
-                mustNotBeNull().
-                mustBe(instanceOf(REnvironment.class));
-
-            String msg1 = "The argument \"package\" to getGeneric";
-            casts.arg(3, "package").
-                defaultError(RError.NO_CALLER, RError.Message.SINGLE_STRING_WRONG_TYPE, msg1, clsHierFn).
-                mustNotBeNull().
-                mustBe(stringValue()).
-                asStringVector().
-                mustBe(singleElement(), RError.NO_CALLER, RError.Message.SINGLE_STRING_TOO_LONG, msg1, vecLenFn).
-                findFirst();
-            //@formatter:on
+            checkSingleString(casts, 0, "f", "The argument \"f\" to getGeneric", true, clsHierFn, vecLenFn);
+
+            casts.arg(1, "mustFind").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
+
+            casts.arg(2, "env").mustBe(instanceOf(REnvironment.class));
+
+            checkSingleString(casts, 3, "package", "The argument \"package\" to getGeneric", false, clsHierFn, vecLenFn);
         }
 
         @Specialization
@@ -435,6 +438,10 @@ public class MethodsListDispatch {
         @Child private LocalReadVariableNode readDotNextMethod;
         @Child private LocalReadVariableNode readDots;
 
+        static {
+            Casts.noCasts(R_nextMethodCall.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected Object nextMethodCall(RLanguage matchedCall, REnvironment ev) {
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 9fca6ad543887ea7ba6d033cdf3a251fa329d9b9..51803d72d1764bc80f4c6244ec3e2eec40ee7c1d 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
@@ -20,7 +20,6 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.UpdateSlotNode;
 import com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen;
-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;
 import com.oracle.truffle.r.nodes.unary.CastToAttributableNode;
@@ -34,12 +33,12 @@ public class Slot {
 
     public abstract static class R_getSlot extends RExternalBuiltinNode.Arg2 {
 
-        @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(false, null, null);
+        @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(false);
         @Child private CastToAttributableNode castAttributable = CastToAttributableNodeGen.create(true, true, true);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg(1, "name").defaultError(RError.NO_CALLER, RError.Message.GENERIC, "invalid type or length for slot name").mustNotBeNull().mustBe(stringValue()).asStringVector().mustBe(
+        static {
+            Casts casts = new Casts(R_getSlot.class);
+            casts.arg(1, "name").defaultError(RError.NO_CALLER, RError.Message.GENERIC, "invalid type or length for slot name").mustBe(stringValue()).asStringVector().mustBe(
                             singleElement()).findFirst().mustBe(Predef.lengthGt(0), RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE);
         }
 
@@ -53,7 +52,7 @@ public class Slot {
             return accessSlotNode.executeAccess(castAttributable.executeObject(object), cachedInternedName);
         }
 
-        @Specialization(contains = "getSlotCached")
+        @Specialization(replaces = "getSlotCached")
         protected Object getSlot(Object object, String name) {
             return accessSlotNode.executeAccess(castAttributable.executeObject(object), getInternedName(name));
         }
@@ -62,12 +61,12 @@ public class Slot {
 
     public abstract static class R_setSlot extends RExternalBuiltinNode.Arg3 {
 
-        @Child private UpdateSlotNode updateSlotNode = UpdateSlotNodeGen.create(null, null, null);
+        @Child private UpdateSlotNode updateSlotNode = UpdateSlotNodeGen.create();
         @Child private CastToAttributableNode castAttributable = CastToAttributableNodeGen.create(true, true, true);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg(1, "name").defaultError(RError.NO_CALLER, RError.Message.GENERIC, "invalid type or length for slot name").mustNotBeNull().mustBe(stringValue()).asStringVector().mustBe(
+        static {
+            Casts casts = new Casts(R_setSlot.class);
+            casts.arg(1, "name").defaultError(RError.NO_CALLER, RError.Message.GENERIC, "invalid type or length for slot name").mustBe(stringValue()).asStringVector().mustBe(
                             singleElement()).findFirst().mustBe(Predef.lengthGt(0), RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE);
         }
 
@@ -81,7 +80,7 @@ public class Slot {
             return updateSlotNode.executeUpdate(castAttributable.executeObject(object), cachedInternedName, value);
         }
 
-        @Specialization(contains = "setSlotCached")
+        @Specialization(replaces = "setSlotCached")
         protected Object setSlot(Object object, String name, Object value) {
             return updateSlotNode.executeUpdate(castAttributable.executeObject(object), getInternedName(name), value);
         }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java
index 10d1a2d64a118f833b65410ea08c6c0f6f205510..e1a2b1bac6bd9299591dc2e0b6c11c65f8a70994 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java
@@ -27,17 +27,26 @@ 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.r.nodes.RASTUtils;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RList2EnvNode;
 import com.oracle.truffle.r.runtime.RError;
+import static com.oracle.truffle.r.runtime.RError.Message.INVALID_LIST_FOR_SUBSTITUTION;
+import static com.oracle.truffle.r.runtime.RError.SHOW_CALLER;
 import com.oracle.truffle.r.runtime.RSubstitute;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public abstract class SubstituteDirect extends RExternalBuiltinNode.Arg2 {
 
+    static {
+        Casts casts = new Casts(SubstituteDirect.class);
+        casts.arg(1).defaultError(SHOW_CALLER, INVALID_LIST_FOR_SUBSTITUTION).mustBe(instanceOf(RAbstractListVector.class).or(instanceOf(REnvironment.class)));
+    }
+
     @Specialization
     @TruffleBoundary
     protected static Object substituteDirect(Object object, REnvironment env) {
@@ -49,18 +58,40 @@ public abstract class SubstituteDirect extends RExternalBuiltinNode.Arg2 {
         }
     }
 
-    @Specialization
+    @Specialization(guards = {"list.getNames() == null || list.getNames().getLength() == 0"})
+    @TruffleBoundary
+    protected static Object substituteDirect(Object object, RList list) {
+        return substituteDirect(object, createNewEnvironment());
+    }
+
+    @Specialization(guards = {"list.getNames() != null", "list.getNames().getLength() > 0"})
     @TruffleBoundary
     protected static Object substituteDirect(Object object, RList list,
-                    @Cached("new()") RList2EnvNode list2Env) {
-        REnvironment env = RDataFactory.createNewEnv(null);
-        env.setParent(REnvironment.baseEnv());
-        list2Env.execute(list, env);
-        return substituteDirect(object, env);
+                    @Cached("createList2EnvNode()") RList2EnvNode list2Env) {
+        return substituteDirect(object, createEnvironment(list, list2Env));
     }
 
     @Fallback
     protected Object substituteDirect(@SuppressWarnings("unused") Object object, @SuppressWarnings("unused") Object env) {
         throw RError.error(this, RError.Message.INVALID_OR_UNIMPLEMENTED_ARGUMENTS);
     }
+
+    @TruffleBoundary
+    public static REnvironment createNewEnvironment() {
+        return createEnvironment(null, null);
+    }
+
+    @TruffleBoundary
+    public static REnvironment createEnvironment(RList list, RList2EnvNode list2Env) {
+        REnvironment env = RDataFactory.createNewEnv(null);
+        env.setParent(REnvironment.baseEnv());
+        if (list2Env != null) {
+            list2Env.execute(list, env);
+        }
+        return env;
+    }
+
+    protected static RList2EnvNode createList2EnvNode() {
+        return new RList2EnvNode(true);
+    }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java
index 2df583879a906d0a99ce1ed127850e9ec01c904a..a5b037c3844d5de7a3bd08403d207286ba008bb7 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/BinDist.java
@@ -22,7 +22,6 @@ import static com.oracle.truffle.r.runtime.RError.NO_CALLER;
 import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -38,8 +37,8 @@ public abstract class BinDist extends RExternalBuiltinNode.Arg5 {
         return BinDistNodeGen.create();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(BinDist.class);
         casts.arg(0).asDoubleVector();
         casts.arg(1).asDoubleVector();
         casts.arg(2).asDoubleVector().findFirst();
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 9664f3ba0886b898ed9862962c2e6e9a4a59c48c..be4422e729caa2e552fa45586ccb92bdd6a0dfad 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
@@ -22,7 +22,6 @@ import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
 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;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -38,8 +37,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
 
     @Child private GetFixedAttributeNode getNamesAttrNode = GetFixedAttributeNode.createNames();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Cdist.class);
         casts.arg(0).asDoubleVector();
         casts.arg(1).asIntegerVector().findFirst();
         casts.arg(2).mustBe(instanceOf(RList.class));
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
index cf77a3c203e680ad2b1c9bd1cd2b32a37ceb0c08..ca606b38331ece53d38741ea3374379b24b950d2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1997-2013,  The R Core Team
- * Copyright (c) 2015, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -34,6 +34,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public final class CompleteCases extends RExternalBuiltinNode {
 
+    static {
+        Casts.noCasts(CompleteCases.class);
+    }
+
     private RError invalidType(Object entry) {
         throw RError.error(this, RError.Message.INVALID_TYPE_ARGUMENT, ((RTypedValue) entry).getRType().getName());
     }
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 8d692d6efcbc18a78ec1214791a4a21770ae8953..05fc0538c7b25a639621064b0dea4015ba5a49b9 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
@@ -23,7 +23,6 @@ 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;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -47,11 +46,11 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         this.isCor = isCor;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Covcor.class);
         casts.arg(0).mustNotBeNull(SHOW_CALLER, Message.IS_NULL, "x").asDoubleVector();
-        casts.arg(1).allowNull().asDoubleVector();
-        casts.arg(2).asIntegerVector().findFirst().mustBe(eq(4), this, Message.NYI, "covcor: other method than 4 not implemented.");
+        casts.arg(1).asDoubleVector();
+        casts.arg(2).asIntegerVector().findFirst().mustBe(eq(4), Message.NYI, "covcor: other method than 4 not implemented.");
         casts.arg(3).asLogicalVector().findFirst().map(toBoolean());
     }
 
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 2d19c386ca9008a469ccea7cbf6119c1eb27d93e..a2de828f383f45478803349ea5674253ff4a63f2 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
@@ -13,7 +13,6 @@ 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.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
@@ -23,8 +22,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Cutree.class);
         casts.arg(0).asIntegerVector();
         casts.arg(1).asIntegerVector();
     }
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 068f611650064146dc53d4a48a67b56d0da36a9b..0eb3928748d7e3ef7d7e41770d2f85d9ffd5e668 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
@@ -13,15 +13,14 @@ 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.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
 public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DoubleCentre.class);
         casts.arg(0).asDoubleVector();
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
index 98ea3435479b0dc1b3f02b745deb1598cd2588b9..c1ea604e1f543e23cfcc47a014e063141898a818 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
@@ -24,7 +24,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 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.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
 import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
@@ -49,8 +48,8 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
         return RMultinomNodeGen.create();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(RMultinomNode.class);
         casts.arg(0).asIntegerVector().findFirst().mustBe(notIntNA(), SHOW_CALLER, Message.INVALID_FIRST_ARGUMENT_NAME, "n");
         casts.arg(1).asIntegerVector().findFirst().mustBe(notIntNA(), SHOW_CALLER, Message.INVALID_SECOND_ARGUMENT_NAME, "size");
         casts.arg(2).asDoubleVector();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
index 07da33f6dc710f901e0d53cc5d5b836ebbd50f01..14f9409f3ec099c5a45cfb569c74874686ec38a2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction
 import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction2NodeGen;
 import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction3NodeGen;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -66,8 +66,8 @@ public final class RandFunctionsNodes {
 
     /**
      * Converts given value to actual length that should be used as length of the output vector. The
-     * argument must be cast using {@link #addLengthCast(CastBuilder)}. Using this node allows us to
-     * avoid casting of long vectors to integers if we only need to know their length.
+     * argument must be cast using {@link #addLengthCast(Casts)}. Using this node allows us to avoid
+     * casting of long vectors to integers if we only need to know their length.
      */
     protected abstract static class ConvertToLength extends Node {
         public abstract int execute(RAbstractVector value);
@@ -89,7 +89,7 @@ public final class RandFunctionsNodes {
             return vector.getLength();
         }
 
-        private static void addLengthCast(CastBuilder casts) {
+        private static void addLengthCast(Casts casts) {
             casts.arg(0).defaultError(SHOW_CALLER, INVALID_UNNAMED_ARGUMENTS).mustBe(abstractVectorValue()).asVector();
         }
     }
@@ -124,7 +124,7 @@ public final class RandFunctionsNodes {
             return evaluateWrapper(lengthVec, a, b, c, randCached, nodeData);
         }
 
-        @Specialization(contains = "evaluateWithCached")
+        @Specialization(replaces = "evaluateWithCached")
         protected final Object evaluateFallback(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand,
                         @Cached("create()") RandGenerationNodeData nodeData) {
             return evaluateWrapper(lengthVec, a, b, c, rand, nodeData);
@@ -262,8 +262,8 @@ public final class RandFunctionsNodes {
             return RandFunction3NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
         }
 
-        @Override
-        protected final void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RandFunction3Node.class);
             ConvertToLength.addLengthCast(casts);
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -292,8 +292,8 @@ public final class RandFunctionsNodes {
             return RandFunction2NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
         }
 
-        @Override
-        protected final void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RandFunction2Node.class);
             ConvertToLength.addLengthCast(casts);
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -321,8 +321,8 @@ public final class RandFunctionsNodes {
             return RandFunction1NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function));
         }
 
-        @Override
-        protected final void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RandFunction1Node.class);
             ConvertToLength.addLengthCast(casts);
             casts.arg(1).asDoubleVector();
         }
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 a16c52363c9303dd5989ea0ef4e50f67daefab72..03b79a3c255bd585bc26178647cadec00635bb40 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
@@ -13,12 +13,24 @@ package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.findFirst;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalError;
+import static com.oracle.truffle.r.runtime.RError.Message.NA_INTRODUCED_COERCION;
+import static com.oracle.truffle.r.runtime.RError.NO_CALLER;
+import static com.oracle.truffle.r.runtime.RRuntime.INT_NA;
 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.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.nmath.RMath;
@@ -32,17 +44,49 @@ import com.oracle.truffle.r.runtime.nmath.RMath;
 public class SplineFunctions {
 
     public abstract static class SplineCoef extends RExternalBuiltinNode.Arg3 {
+        static {
+            Casts casts = new Casts(SplineCoef.class);
+            casts.arg(0).mapNull(constant(INT_NA)).mapIf(numericValue(),
+                            chain(asIntegerVector()).with(findFirst().integerElement(INT_NA)).end(),
+                            chain(asIntegerVector()).with(findFirst().integerElement(INT_NA)).with(
+                                            Predef.shouldBe(integerValue(), NO_CALLER, NA_INTRODUCED_COERCION)).end());
+            casts.arg(1).allowMissing().asDoubleVector();
+            casts.arg(2).allowMissing().asDoubleVector();
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object splineCoef(int method, RAbstractDoubleVector x, RAbstractDoubleVector y) {
+            return SplineFunctions.splineCoef(method, x.materialize(), y.materialize());
+        }
 
         @Specialization
         @TruffleBoundary
-        protected Object splineCoef(Object method, RAbstractDoubleVector x, RAbstractDoubleVector y) {
-            int methodInt = castInt(castVector(method));
-            return SplineFunctions.splineCoef(methodInt, x.materialize(), y.materialize());
+        protected Object splineCoef(int method, RAbstractDoubleVector x, RNull y) {
+            return SplineFunctions.splineCoef(method, x.materialize(), RDataFactory.createDoubleVector(0));
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object splineCoef(int method, RNull x, RAbstractDoubleVector y) {
+            return SplineFunctions.splineCoef(method, RDataFactory.createDoubleVector(0), y.materialize());
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object splineCoef(int method, RNull x, RNull y) {
+            return SplineFunctions.splineCoef(method, RDataFactory.createDoubleVector(0), RDataFactory.createDoubleVector(0));
         }
     }
 
     public abstract static class SplineEval extends RExternalBuiltinNode.Arg2 {
 
+        static {
+            Casts casts = new Casts(SplineEval.class);
+            casts.arg(0, "xout").mustBe(doubleValue()).asDoubleVector();
+            casts.arg(1, "z").mustBe(instanceOf(RList.class));
+        }
+
         @Specialization
         @TruffleBoundary
         protected Object splineEval(RAbstractDoubleVector xout, RList z) {
@@ -99,7 +143,9 @@ public class SplineFunctions {
 
         double[] e = new double[n];
 
-        RInternalError.guarantee(n >= 2 && y[0] == y[n - 1], "periodic spline: domain error");
+        if (n < 2 || y[0] != y[n - 1]) {
+            return;
+        }
 
         if (n == 2) {
             b[0] = 0.0;
@@ -215,7 +261,9 @@ public class SplineFunctions {
         int i;
         double t;
 
-        RInternalError.guarantee(n >= 2, "periodic spline: domain error");
+        if (n < 2) {
+            return;
+        }
 
         if (n < 3) {
             t = (y[1] - y[0]);
@@ -289,7 +337,9 @@ public class SplineFunctions {
         int i;
         double t;
 
-        RInternalError.guarantee(n >= 2, "periodic spline: domain error");
+        if (n < 2) {
+            return;
+        }
 
         if (n < 3) {
             t = (y[1] - y[0]);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
index 5ea680278a4d36207f0c5ecc3febd9e228d1da61..11a0662bdfafa8f80dd5bbb6728c4a0adbfc4c3f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
@@ -30,7 +30,6 @@ import com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function3_2
 import com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function4_1NodeGen;
 import com.oracle.truffle.r.library.stats.StatsFunctionsNodesFactory.Function4_2NodeGen;
 import com.oracle.truffle.r.nodes.attributes.UnaryCopyAttributesNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -149,8 +148,8 @@ public final class StatsFunctionsNodes {
             return Function3_2NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function3_2Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -177,8 +176,8 @@ public final class StatsFunctionsNodes {
             return Function4_1NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function4_1Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -205,8 +204,8 @@ public final class StatsFunctionsNodes {
             return Function4_2NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function4_2Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -234,8 +233,8 @@ public final class StatsFunctionsNodes {
             return Function3_1NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function3_1Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asDoubleVector();
@@ -261,8 +260,8 @@ public final class StatsFunctionsNodes {
             return Function2_1NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function2_1Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asLogicalVector().findFirst().map(toBoolean());
@@ -287,8 +286,8 @@ public final class StatsFunctionsNodes {
             return Function2_2NodeGen.create(function);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Function2_2Node.class);
             casts.arg(0).asDoubleVector();
             casts.arg(1).asDoubleVector();
             casts.arg(2).asLogicalVector().findFirst().map(toBoolean());
@@ -308,8 +307,8 @@ public final class StatsFunctionsNodes {
             return ApproxTestNodeGen.create();
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ApproxTest.class);
             casts.arg(2).asIntegerVector().findFirst();
             casts.arg(3).asDoubleVector().findFirst();
         }
@@ -346,8 +345,8 @@ public final class StatsFunctionsNodes {
             return ApproxNodeGen.create();
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Approx.class);
             casts.arg(2).asDoubleVector();
             casts.arg(3).asIntegerVector().findFirst();
             casts.arg(4).asDoubleVector().findFirst();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R
index 3245db800939dc6f30c42f3e67bee168579ac8ae..37640f855ba9e0ec96d6831e6d6abb188f944f2c 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R
@@ -5,7 +5,7 @@
 #
 # Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
 # Copyright (c) 1997-2013,  The R Core Team
-# Copyright (c) 2016, Oracle and/or its affiliates
+# Copyright (c) 2016, 2017 Oracle and/or its affiliates
 #
 # All rights reserved.
 #
@@ -166,7 +166,7 @@ ExtractVars <- function (formula, checkonly=FALSE) {
         if (identical(op, quote(`~`))) { # tilde
             if (response) {
                 error("invalid model formula")
-            } else if (is.null(formula[[3]])) {
+            } else if (length(formula) < 3 || is.null(formula[[3]])) {
                 response <<- FALSE
                 ExtractVars(formula[[2]], FALSE)
             } else {
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 4eab6dfc718fa092d6d56eec4234770ad1e5b21e..915a54f6139f5840e36e127a899765f663abec06 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
@@ -22,60 +22,69 @@
  */
 package com.oracle.truffle.r.library.tools;
 
-import java.io.IOException;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 
 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.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.ffi.AsIntegerNode;
+import com.oracle.truffle.r.nodes.ffi.AsLogicalNode;
 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.conn.RConnection;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 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();
+    @Child ToolsRFFI.ParseRdNode parseRdNode = RFFIFactory.getRFFI().getToolsRFFI().createParseRdNode();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(0).defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
-    }
-
-    @Specialization
-    protected Object parseRd(int con, REnvironment srcfile, String encoding, byte verboseL, RAbstractStringVector basename, byte fragmentL, byte warningCallsL, byte macrosL, byte warndupsL) {
-        return doParseRd(con, srcfile, encoding, verboseL, basename, fragmentL, warningCallsL, RDataFactory.createLogicalVectorFromScalar(macrosL), warndupsL);
-    }
-
-    @Specialization
-    protected Object parseRd(int con, REnvironment srcfile, String encoding, byte verboseL, RAbstractStringVector basename, byte fragmentL, byte warningCallsL, REnvironment macros, byte warndupsL) {
-        return doParseRd(con, srcfile, encoding, verboseL, basename, fragmentL, warningCallsL, macros, warndupsL);
+    static {
+        Casts casts = new Casts(C_ParseRd.class);
+        /*
+         * Most arguments require coercion using, e.g., asLogical; N.B. GNU R doesn't check
+         * everything, e.g., srcfile. Since this is "internal" code we do not really expect argument
+         * errors.
+         */
+        casts.arg(1, "srcfile").mustBe(instanceOf(REnvironment.class));
+        casts.arg(3, "verbose").mustBe(logicalValue()).asLogicalVector();
+        casts.arg(4, "basename").mustBe(stringValue()).asStringVector();
     }
 
     @TruffleBoundary
-    private Object doParseRd(int con, REnvironment srcfile, @SuppressWarnings("unused") String encoding, byte verboseL, RAbstractStringVector basename, byte fragmentL, byte warningCallsL,
-                    Object macros, byte warndupsL) {
-        if (RRuntime.isNA(warningCallsL)) {
-            throw RError.error(this, RError.Message.INVALID_ARGUMENT, "warningCalls");
+    @Specialization
+    protected Object parseRd(Object conObj, REnvironment srcfile, @SuppressWarnings("unused") Object encoding, RAbstractLogicalVector verbose, RAbstractStringVector basename, Object fragmentObj,
+                    Object warningCallsObj, Object macros, Object warndupsObj,
+                    @Cached("create()") AsIntegerNode conAsInteger,
+                    @Cached("create()") AsLogicalNode fragmentAsLogical,
+                    @Cached("create()") AsLogicalNode warningCallsAsLogical,
+                    @Cached("create()") AsLogicalNode warnDupsAsLogical) {
+        int con = conAsInteger.execute(conObj);
+        int warningCalls = warningCallsAsLogical.execute(warningCallsObj);
+        if (RRuntime.isNA(warningCalls)) {
+            throw RError.error(this, RError.Message.INVALID_VALUE, "warningCalls");
         }
+        int fragment = fragmentAsLogical.execute(fragmentObj);
+        int warndups = warnDupsAsLogical.execute(warndupsObj);
 
+        // fromIndex checks validity of con and throws error if not
         try (RConnection openConn = RConnection.fromIndex(con).forceOpen("r")) {
             // @formatter:off
-            return toolsRFFINode.parseRd(openConn, srcfile,
-                            RDataFactory.createLogicalVectorFromScalar(verboseL),
-                            RDataFactory.createLogicalVectorFromScalar(fragmentL),
-                            RDataFactory.createStringVectorFromScalar(basename.getDataAt(0)),
-                            RDataFactory.createLogicalVectorFromScalar(warningCallsL),
+            return parseRdNode.execute(openConn, srcfile,
+                            verbose.materialize(),
+                            RDataFactory.createLogicalVectorFromScalar((byte) fragment),
+                            basename.materialize(),
+                            RDataFactory.createLogicalVectorFromScalar((byte) warningCalls),
                             macros,
-                            RDataFactory.createLogicalVectorFromScalar(warndupsL));
+                            RDataFactory.createLogicalVectorFromScalar((byte) warndups));
             // @formatter:on
-        } catch (IOException ex) {
-            throw RError.error(this, RError.Message.GENERIC, ex.getMessage());
         } catch (Throwable ex) {
             throw RError.error(this, RError.Message.GENERIC, ex.getMessage());
         }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
index c86c881af6e0575bae198a4ef26cd2ec98a74a30..9685b25687c58acaaac849aabf0e6e646fc11538 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java
@@ -24,15 +24,15 @@ import java.util.Iterator;
 import java.util.stream.Stream;
 
 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.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
 
@@ -41,15 +41,16 @@ public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
     private static final int FILE_MASK = 0644;
     private static final int DIR_MASK = 0755;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(0, "dir").mustNotBeNull().mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
+    static {
+        Casts casts = new Casts(DirChmod.class);
+        casts.arg(0, "dir").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         casts.arg(1).asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
     }
 
     @Specialization
     @TruffleBoundary
-    protected RNull dirChmod(String pathName, boolean setGroupWrite) {
+    protected RNull dirChmod(String pathName, boolean setGroupWrite,
+                    @Cached("create()") BaseRFFI.ChmodNode chmodNode) {
         Path path = FileSystems.getDefault().getPath(pathName);
         int fileMask = setGroupWrite ? GRPWRITE_FILE_MASK : FILE_MASK;
         int dirMask = setGroupWrite ? GRPWRITE_DIR_MASK : DIR_MASK;
@@ -65,7 +66,7 @@ public abstract class DirChmod extends RExternalBuiltinNode.Arg2 {
                 int elementMode = Utils.intFilePermissions(pfa.permissions());
                 int newMode = Files.isDirectory(element) ? elementMode | dirMask : elementMode | fileMask;
                 // System.out.printf("path %s: old %o, new %o%n", element, elementMode, newMode);
-                RFFIFactory.getRFFI().getBaseRFFI().chmod(element.toString(), newMode);
+                chmodNode.execute(element.toString(), newMode);
             }
         } catch (IOException ex) {
             // ignore
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java
index 647ed04d9818905b32a142641e10af0d5790ca2e..7b9d09c4a88998f7960e151953c037d2432275b1 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/Rmd5.java
@@ -33,7 +33,6 @@ import java.security.NoSuchAlgorithmException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -45,9 +44,9 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class Rmd5 extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(0).defaultError(RError.NO_CALLER, RError.Message.ARG_MUST_BE_CHARACTER, "files").mustNotBeNull().mustBe(stringValue());
+    static {
+        Casts casts = new Casts(Rmd5.class);
+        casts.arg(0).defaultError(RError.NO_CALLER, RError.Message.ARG_MUST_BE_CHARACTER, "files").mustBe(stringValue());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java
index bb328a40e236e90258c724bfd882acc0d39df6ca..576ff1bd5571c60a5808cddb9a6da9a002ebe27e 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java
@@ -11,6 +11,7 @@
  */
 package com.oracle.truffle.r.library.tools;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
@@ -24,8 +25,6 @@ import java.nio.file.Path;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -37,11 +36,10 @@ public class ToolsText {
 
     public abstract static class DoTabExpand extends RExternalBuiltinNode.Arg2 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg(0, "strings").defaultError(RError.NO_CALLER, RError.Message.MACRO_CAN_BE_APPLIED_TO, "STRING_ELT()", "character vector", typeName()).mustNotBeNull().mustBe(stringValue());
-            casts.arg(1, "starts").defaultError(RError.NO_CALLER, RError.Message.MACRO_CAN_BE_APPLIED_TO, "INTEGER()", "integer", typeName()).mustNotBeNull().mustBe(
-                            Predef.integerValue()).asIntegerVector();
+        static {
+            Casts casts = new Casts(DoTabExpand.class);
+            casts.arg(0, "strings").defaultError(RError.NO_CALLER, RError.Message.MACRO_CAN_BE_APPLIED_TO, "STRING_ELT()", "character vector", typeName()).mustBe(stringValue());
+            casts.arg(1, "starts").defaultError(RError.NO_CALLER, RError.Message.MACRO_CAN_BE_APPLIED_TO, "INTEGER()", "integer", typeName()).mustBe(integerValue()).asIntegerVector();
         }
 
         @Specialization
@@ -80,10 +78,10 @@ public class ToolsText {
 
     public abstract static class CodeFilesAppend extends RExternalBuiltinNode.Arg2 {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg(0, "file1").mustNotBeNull().mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
-            casts.arg(1, "file2").mustNotBeNull().mustBe(stringValue()).asStringVector();
+        static {
+            Casts casts = new Casts(CodeFilesAppend.class);
+            casts.arg(0, "file1").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
+            casts.arg(1, "file2").mustBe(stringValue()).asStringVector();
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java
index 3e898dc731637e138cbf18255152c20d5e0dc14b..cb470182d58a282b25717ef630d53db7111478a2 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java
@@ -53,6 +53,10 @@ public final class CountFields extends RExternalBuiltinNode {
 
     }
 
+    static {
+        Casts.noCasts(CountFields.class);
+    }
+
     @TruffleBoundary
     private static Object countFields(RConnection file, char sepChar, String quoteSet, @SuppressWarnings("unused") int nskip, boolean blskip, char comChar) throws IOException {
         LocalData data = new LocalData();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java
index e0427687483512b5ab3882cd3c2c1c0ec52f2181..51eb47a457af6a813af1e9f27691829cd8aad73f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Crc64.java
@@ -26,15 +26,14 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class Crc64 extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Crc64.class);
         casts.arg(0).mustNotBeNull(RError.NO_CALLER,
                         RError.Message.INPUT_MUST_BE_STRING).mustBe(stringValue(), RError.NO_CALLER, RError.Message.INPUT_MUST_BE_STRING);
     }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java
index d0f9a689e54623023ba267367ebceafb62fb617b..00172482920056c2d34e3ed7af95a425f2b768af 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Download.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.library.utils;
 
+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.singleElement;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
@@ -36,8 +37,6 @@ import java.nio.file.StandardCopyOption;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -48,13 +47,13 @@ import com.oracle.truffle.r.runtime.RError.Message;
  */
 public abstract class Download extends RExternalBuiltinNode.Arg5 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(0).mustNotBeNull().mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
-        casts.arg(1).mustNotBeNull().mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
-        casts.arg(2).mustNotBeNull().mustBe(Predef.logicalValue()).asLogicalVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst().map(toBoolean());
-        casts.arg(3).mustNotBeNull().mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
-        casts.arg(4).mustNotBeNull().mustBe(Predef.logicalValue()).asLogicalVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst().map(toBoolean());
+    static {
+        Casts casts = new Casts(Download.class);
+        casts.arg(0).mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
+        casts.arg(1).mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
+        casts.arg(2).mustBe(logicalValue()).asLogicalVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst().map(toBoolean());
+        casts.arg(3).mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst();
+        casts.arg(4).mustBe(logicalValue()).asLogicalVector().mustBe(notEmpty()).shouldBe(singleElement(), Message.ONLY_FIRST_USED).findFirst().map(toBoolean());
 
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java
index 23ebf09462371c1da3756e3f5957f7fcba12a035..05fca52ffdc56ddf24dba599db1f3502def339bc 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Menu.java
@@ -14,7 +14,6 @@ package com.oracle.truffle.r.library.utils;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.runtime.RError;
@@ -26,8 +25,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class Menu extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Menu.class);
         casts.arg(0, "choices").mustBe(Predef.stringValue()).asStringVector().mustBe(Predef.notEmpty());
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java
index 46b2c62146024cecb24ae79e2fd6c4269a0fd4a0..8c17ea3fb61df57b4757e4bd49e01f024da0e3e3 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
  * {@link RObjectSize#getObjectSize}. As per GNU R the AST size for a closure is included. TODO AST
  * size not included owing to problems sizing it automatically.
  */
-@SuppressWarnings("unused")
 public abstract class ObjectSize extends RExternalBuiltinNode.Arg1 {
 
     private static class MyIgnoreObjectHandler implements RObjectSize.IgnoreObjectHandler {
@@ -52,17 +51,17 @@ public abstract class ObjectSize extends RExternalBuiltinNode.Arg1 {
     private static final MyIgnoreObjectHandler ignoreObjectHandler = new MyIgnoreObjectHandler();
 
     @Specialization
-    protected int objectSize(int o) {
+    protected int objectSize(@SuppressWarnings("unused") int o) {
         return RObjectSize.INT_SIZE;
     }
 
     @Specialization
-    protected int objectSize(double o) {
+    protected int objectSize(@SuppressWarnings("unused") double o) {
         return RObjectSize.DOUBLE_SIZE;
     }
 
     @Specialization
-    protected int objectSize(byte o) {
+    protected int objectSize(@SuppressWarnings("unused") byte o) {
         return RObjectSize.BYTE_SIZE;
     }
 
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
index 784bd50cfe616d4cbaba957fa1bd9c1f2908fa67..e91e16f85ac3d9346efccf14ad73c3d4497806aa 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
@@ -40,7 +40,6 @@ import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
 import com.oracle.truffle.api.instrumentation.StandardTags;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.Source;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
@@ -56,7 +55,6 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RObjectSize;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
@@ -82,8 +80,8 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
  */
 public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFactory.Listener, MemoryCopyTracer.Listener {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Rprof.class);
         casts.arg(0, "filename").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         casts.arg(1, "append_mode").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
         casts.arg(2, "dinterval").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
@@ -94,11 +92,10 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
         casts.arg(7, "bufsize").asIntegerVector().findFirst().mustBe(gte(0));
     }
 
-    @SuppressWarnings("unused")
     @Specialization
     @TruffleBoundary
-    public Object doRprof(String filename, boolean append, double intervalD, boolean memProfiling,
-                    boolean gcProfiling, boolean lineProfiling, int numFiles, int bufSize) {
+    public Object doRprof(String filename, boolean append, double intervalD, boolean memProfiling, boolean gcProfiling, boolean lineProfiling, @SuppressWarnings("unused") int numFiles,
+                    @SuppressWarnings("unused") int bufSize) {
         RprofState profState = RprofState.get();
         if (filename.length() == 0) {
             // disable
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprofmem.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprofmem.java
index e96b554c9dca7fd74c1add7b9f09ccdd29569959..9500f6f83e4113de60775b842c033a22b0eecc85 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprofmem.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprofmem.java
@@ -30,6 +30,9 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.nodes.Node;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RError;
@@ -48,6 +51,13 @@ import com.oracle.truffle.r.runtime.instrument.InstrumentationState.RprofState;
 
 public abstract class Rprofmem extends RExternalBuiltinNode.Arg3 implements RDataFactory.Listener {
 
+    static {
+        Casts casts = new Casts(Rprofmem.class);
+        casts.arg(0, "filename").mustBe(stringValue()).asStringVector();
+        casts.arg(1, "append").mustBe(instanceOf(byte.class));
+        casts.arg(2, "threshold").mustBe(doubleValue()).asDoubleVector();
+    }
+
     @Specialization
     @TruffleBoundary
     public Object doRprofmem(RAbstractStringVector filenameVec, byte appendL, RAbstractDoubleVector thresholdVec) {
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 81362811de3c5143b33e6276efeece26e09e6920..27d158bbc8bae512d152b6ea83ef2e9a44258e5f 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
@@ -27,20 +27,40 @@ import java.util.TreeSet;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asLogicalVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.findFirst;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.map;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import static com.oracle.truffle.r.runtime.RError.Message.FIRST_ARGUMENT_MUST_BE_CHARACTER;
+import static com.oracle.truffle.r.runtime.RError.Message.INVALID_ARG;
+import static com.oracle.truffle.r.runtime.RError.SHOW_CALLER;
 import com.oracle.truffle.r.runtime.RRuntime;
+import static com.oracle.truffle.r.runtime.RRuntime.LOGICAL_FALSE;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
 
     @Child private SetFixedAttributeNode setLevelsAttrNode = SetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
 
+    static {
+        Casts casts = new Casts(TypeConvert.class);
+        casts.arg(0).mustBe(stringValue(), SHOW_CALLER, FIRST_ARGUMENT_MUST_BE_CHARACTER).asStringVector();
+        casts.arg(1).mustBe(stringValue(), SHOW_CALLER, INVALID_ARG, "'na.strings'").asStringVector();
+        casts.arg(2).mapIf(logicalValue(),
+                        chain(asLogicalVector()).with(findFirst().logicalElement(LOGICAL_FALSE)).with(toBoolean()).end(),
+                        chain(map(constant(LOGICAL_FALSE))).with(toBoolean()).end());
+    }
+
     private static boolean isNA(String s, RAbstractStringVector naStrings) {
         // naStrings are in addition to NA_character_
         if (RRuntime.isNA(s)) {
@@ -106,7 +126,7 @@ public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
     }
 
     @Specialization
-    protected Object typeConvert(RAbstractStringVector x, RAbstractStringVector naStrings, byte asIs, @SuppressWarnings("unused") Object dec, @SuppressWarnings("unused") Object numeral) {
+    protected Object typeConvert(RAbstractStringVector x, RAbstractStringVector naStrings, boolean asIs, @SuppressWarnings("unused") Object dec, @SuppressWarnings("unused") Object numeral) {
         if (x.getLength() == 0) {
             return RDataFactory.createEmptyLogicalVector();
         }
@@ -161,7 +181,7 @@ public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
         }
         // fall through target - conversion to int, double or logical failed
 
-        if (asIs == RRuntime.LOGICAL_TRUE) {
+        if (asIs) {
             return x;
         } else {
             // create a factor
diff --git a/com.oracle.truffle.r.native/Makefile b/com.oracle.truffle.r.native/Makefile
index 2b59c073ff66292a1acdc7318c2385a98a9da7c5..37ea9afada6df6eab8e1cd5c66f064969d37200a 100644
--- a/com.oracle.truffle.r.native/Makefile
+++ b/com.oracle.truffle.r.native/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -30,12 +30,17 @@ export FASTR_NATIVE_DIR = $(TOPDIR)
 export R_VERSION = $(subst R-,,$(notdir $(basename $(basename $(wildcard $(FASTR_R_HOME)/libdownloads/R-*.gz)))))
 export GNUR_HOME = $(TOPDIR)/gnur/R-$(R_VERSION)
 
-all: 
+# Completely accurate dependency analysis is very difficult for this project, so use a version number
+# to force a clean build, and elsewhere use sentinels to avoid rebuilding when we can't compute the 
+# dependencies accurately.
+
+all: checkversion
 	$(MAKE) -C gnur
 	$(MAKE) -C include
 	$(MAKE) -C fficall
 	$(MAKE) -C library
 	$(MAKE) -C run
+	cp version.source version.built
 
 clean: 
 	$(MAKE) -C include clean
@@ -44,3 +49,23 @@ clean:
 	$(MAKE) -C run clean
 	$(MAKE) -C gnur clean
 
+version.source := $(shell cat version.source)
+
+#$(info version: $(version.source))
+ifeq ($(wildcard version.built),)
+	doclean = 1
+else
+version.built := $(shell cat version.built)
+#$(info version.built: $(version.built))
+ifneq ($(version.source),$(version.built))
+	doclean = 1
+else
+	doclean = 0
+endif
+endif
+
+#$(info doclean: $(doclean))
+checkversion:
+ifeq ($(doclean),1)
+	$(MAKE) clean
+endif
diff --git a/com.oracle.truffle.r.native/fficall/Makefile b/com.oracle.truffle.r.native/fficall/Makefile
index dbbd428176014064c69dfcefebb80ce6b495f70d..78b1f4b0c3f55fb10f8180ab0b4492966b9645f5 100644
--- a/com.oracle.truffle.r.native/fficall/Makefile
+++ b/com.oracle.truffle.r.native/fficall/Makefile
@@ -72,7 +72,7 @@ jni.done:
 	$(MAKE) -C src/common all
 	$(MAKE) -C src/jni all
 ifeq ($(HAVE_SULONG),yes)
-	$(MAKE) -C src/truffle all
+	$(MAKE) -C src/truffle_llvm all
 endif
 	touch jni.done
 
@@ -90,7 +90,7 @@ clean:
 	$(MAKE) -C src/common clean
 	$(MAKE) -C src/jni clean
 ifeq ($(HAVE_SULONG),yes)
-	$(MAKE) -C src/truffle clean
+	$(MAKE) -C src/truffle_llvm clean
 endif
 	rm -rf $(R_LIB)
 	rm -rf $(JNIBOOT_LIB)
diff --git a/com.oracle.truffle.r.native/fficall/src/common/coerce_fastr.c b/com.oracle.truffle.r.native/fficall/src/common/coerce_fastr.c
index a49307a11779bc2093e0410ad88ebc71d4a5f449..764b8be1bb08953dca725303fa8dacf3312c34ff 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/coerce_fastr.c
+++ b/com.oracle.truffle.r.native/fficall/src/common/coerce_fastr.c
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -308,155 +308,3 @@ static SEXP coercePairList(SEXP v, SEXPTYPE type)
     return rval;
 }
 
-SEXP Rf_coerceVector(SEXP v, SEXPTYPE type)
-{
-    SEXP op, vp, ans = R_NilValue;	/* -Wall */
-    int i,n;
-
-    if (TYPEOF(v) == type)
-	return v;
-    /* code to allow classes to extend ENVSXP, SYMSXP, etc */
-    if(IS_S4_OBJECT(v) && TYPEOF(v) == S4SXP) {
-	SEXP vv = R_getS4DataSlot(v, ANYSXP);
-	if(vv == R_NilValue)
-	  error(_("no method for coercing this S4 class to a vector"));
-	else if(TYPEOF(vv) == type)
-	  return vv;
-	v = vv;
-    }
-
-    switch (TYPEOF(v)) {
-#ifdef NOTYET
-    case NILSXP:
-	ans = coerceNull(v, type);
-	break;
-#endif
-    case SYMSXP:
-	ans = coerceSymbol(v, type);
-	break;
-    case NILSXP:
-    case LISTSXP:
-	ans = coercePairList(v, type);
-	break;
-    case LANGSXP:
-	if (type != STRSXP) {
-	    ans = coercePairList(v, type);
-	    break;
-	}
-
-	/* This is mostly copied from coercePairList, but we need to
-	 * special-case the first element so as not to get operators
-	 * put in backticks. */
-	n = length(v);
-	PROTECT(ans = allocVector(type, n));
-	if (n == 0) break; /* Can this actually happen? */
-	i = 0;
-	op = CAR(v);
-	/* The case of practical relevance is "lhs ~ rhs", which
-	 * people tend to split using as.character(), modify, and
-	 * paste() back together. However, we might as well
-	 * special-case all symbolic operators here. */
-	if (TYPEOF(op) == SYMSXP) {
-	    SET_STRING_ELT(ans, i, PRINTNAME(op));
-	    i++;
-	    v = CDR(v);
-	}
-
-	/* The distinction between strings and other elements was
-	 * here "always", but is really dubious since it makes x <- a
-	 * and x <- "a" come out identical. Won't fix just now. */
-	for (vp = v;  vp != R_NilValue; vp = CDR(vp), i++) {
-	    if (isString(CAR(vp)) && length(CAR(vp)) == 1)
-		SET_STRING_ELT(ans, i, STRING_ELT(CAR(vp), 0));
-	    else
-		SET_STRING_ELT(ans, i, STRING_ELT(deparse1line(CAR(vp), 0), 0));
-	}
-	UNPROTECT(1);
-	break;
-    case VECSXP:
-    case EXPRSXP:
-	ans = coerceVectorList(v, type);
-	break;
-    case ENVSXP:
-	error(_("environments cannot be coerced to other types"));
-	break;
-    case LGLSXP:
-    case INTSXP:
-    case REALSXP:
-    case CPLXSXP:
-    case STRSXP:
-    case RAWSXP:
-
-#define COERCE_ERROR_STRING "cannot coerce type '%s' to vector of type '%s'"
-
-#define COERCE_ERROR							\
-	error(_(COERCE_ERROR_STRING), type2char(TYPEOF(v)), type2char(type))
-
-	switch (type) {
-	case SYMSXP:
-	    ans = coerceToSymbol(v);	    break;
-	case LGLSXP:
-	    ans = coerceToLogical(v);	    break;
-	case INTSXP:
-	    ans = coerceToInteger(v);	    break;
-	case REALSXP:
-	    ans = coerceToReal(v);	    break;
-	case CPLXSXP:
-	    ans = coerceToComplex(v);	    break;
-	case RAWSXP:
-	    ans = coerceToRaw(v);	    break;
-	case STRSXP:
-	    ans = coerceToString(v);	    break;
-	case EXPRSXP:
-	    ans = coerceToExpression(v);    break;
-	case VECSXP:
-	    ans = coerceToVectorList(v);    break;
-	case LISTSXP:
-	    ans = coerceToPairList(v);	    break;
-	default:
-	    COERCE_ERROR;
-	}
-	break;
-    default:
-	COERCE_ERROR;
-    }
-    return ans;
-}
-#undef COERCE_ERROR
-
-
-double Rf_asReal(SEXP x)
-{
-    int warn = 0;
-    double res;
-
-    if (isVectorAtomic(x) && XLENGTH(x) >= 1) {
-	switch (TYPEOF(x)) {
-	case LGLSXP:
-	    res = RealFromLogical(LOGICAL(x)[0], &warn);
-	    CoercionWarning(warn);
-	    return res;
-	case INTSXP:
-	    res = RealFromInteger(INTEGER(x)[0], &warn);
-	    CoercionWarning(warn);
-	    return res;
-	case REALSXP:
-	    return REAL(x)[0];
-	case CPLXSXP:
-	    res = RealFromComplex(COMPLEX(x)[0], &warn);
-	    CoercionWarning(warn);
-	    return res;
-	case STRSXP:
-	    res = RealFromString(STRING_ELT(x, 0), &warn);
-	    CoercionWarning(warn);
-	    return res;
-	default:
-	    UNIMPLEMENTED_TYPE("asReal", x);
-	}
-    } else if(TYPEOF(x) == CHARSXP) {
-	res = RealFromString(x, &warn);
-	CoercionWarning(warn);
-	return res;
-    }
-    return NA_REAL;
-}
diff --git a/com.oracle.truffle.r.native/fficall/src/include/Defn.h b/com.oracle.truffle.r.native/fficall/src/include/Defn.h
index 2b4d813d23ac84d29dd8e6990d3c4f440ddc9e07..b401a7c0b7a2efedd0b9f55e0aed231895e92754 100644
--- a/com.oracle.truffle.r.native/fficall/src/include/Defn.h
+++ b/com.oracle.truffle.r.native/fficall/src/include/Defn.h
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -46,13 +46,18 @@ void Rf_checkArityCall(SEXP, SEXP, SEXP);
 /* ../main/devices.c, used in memory.c, gnuwin32/extra.c */
 #define R_MaxDevices 64
 
-extern SEXP R_DeviceSymbol;
-extern SEXP R_DevicesSymbol;
-extern Rboolean R_Interactive;
+extern SEXP FASTR_R_DevicesSymbol();
+#define R_DevicesSymbol FASTR_R_DevicesSymbol()
+extern SEXP FASTR_R_DeviceSymbol();
+#define R_DeviceSymbol FASTR_R_DeviceSymbol()
+extern Rboolean FASTR_R_Interactive();
+#define R_Interactive FASTR_R_Interactive()
 extern Rboolean R_Visible;
 int	R_ReadConsole(const char *, unsigned char *, int, int);
-extern const char *R_Home;
-extern const char *R_TempDir;
+extern const char *FASTR_R_Home();
+#define R_Home FASTR_R_Home()
+extern const char *FASTR_R_TempDir();
+#define R_TempDir FASTR_R_TempDir()
 
 //#define HAVE_MBSTATE_T 1 // actually from config.h
 
diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Makefile b/com.oracle.truffle.r.native/fficall/src/jni/Makefile
index cf8d9aea8681906c42d287dfffed4a0a5278beae..fbbb5f7439dba6a5a6e0c261645d4a25922585f1 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Makefile
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -53,7 +53,7 @@ $(OBJ):
 	mkdir -p $(OBJ)
 
 $(OBJ)/%.o: %.c $(TOPDIR)/include/Rinternals.h $(C_HDRS)
-	$(CC) $(CFLAGS) $(INCLUDES) -I../variable_defs -c $< -o $@
+	$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
 
 # for debugging, to see what's really being compiled
 $(OBJ)/%.E: %.c $(TOPDIR)/include/Rinternals.h
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 233a58dbc129066a73b9a1cb364bc7cffde33b1a..723290cfea319d97cce90c45762f13087bd4ed28 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Parse.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@ static jfieldID parseExprFieldID;
 
 void init_parse(JNIEnv *env) {
 	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");
+	parseResultClass = checkFindClass(env, "com/oracle/truffle/r/nodes/ffi/ParseResult");
 	parseStatusFieldID = checkGetFieldID(env, parseResultClass, "parseStatus", "I", 0);
 	parseExprFieldID = checkGetFieldID(env, parseResultClass, "expr", "Ljava/lang/Object;", 0);
 }
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 22ad74dcdfdec1f899db788decbb88905e35ee15..c9b70d1372a81627aed4d2e6a8c8343ea36edf20 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2015, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -190,6 +190,7 @@ void R_SaveGlobalEnvToFile(const char *f) {
 
 void R_Suicide(const char *s) { ptr_R_Suicide(s); }
 
+#undef R_Interactive
 
 void R_DefParams(Rstart rs) {
     // These are the GnuR defaults and correspond to the settings in RStartParams
@@ -235,7 +236,7 @@ void R_set_command_line_arguments(int argc, char **argv) {
 
 int Rf_initEmbeddedR(int argc, char *argv[]) {
 	Rf_initialize_R(argc, argv);
-	R_Interactive = TRUE;
+//	R_Interactive = TRUE;
     setup_Rmainloop();
     return 1;
 }
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 540621ad1600f0694ab8c21c598f3fbe7efd6dcf..affaab5f727fbad00ec93247b196107031d0d2f7 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -90,8 +90,9 @@ static jmethodID STRING_ELT_MethodID;
 static jmethodID VECTOR_ELT_MethodID;
 static jmethodID LENGTH_MethodID;
 static jmethodID Rf_asIntegerMethodID;
-//static jmethodID Rf_asRealMethodID;
+static jmethodID Rf_asRealMethodID;
 static jmethodID Rf_asCharMethodID;
+static jmethodID Rf_coerceVectorMethodID;
 static jmethodID Rf_mkCharLenCEMethodID;
 static jmethodID Rf_asLogicalMethodID;
 static jmethodID Rf_PairToVectorListMethodID;
@@ -101,7 +102,7 @@ static jmethodID SET_TYPEOF_FASTR_MethodID;
 static jmethodID TYPEOF_MethodID;
 static jmethodID OBJECT_MethodID;
 static jmethodID DUPLICATE_ATTRIB_MethodID;
-static jmethodID isS4ObjectMethodID;
+static jmethodID IS_S4_OBJECTMethodID;
 static jmethodID logNotCharSXPWrapperMethodID;
 static jmethodID R_tryEvalMethodID;
 static jmethodID RDEBUGMethodID;
@@ -112,6 +113,10 @@ static jmethodID ENCLOSMethodID;
 static jmethodID PRVALUEMethodID;
 static jmethodID R_lsInternal3MethodID;
 static jmethodID R_do_MAKE_CLASS_MethodID;
+static jmethodID PRSEENMethodID;
+static jmethodID PRENVMethodID;
+static jmethodID R_PromiseExprMethodID;
+static jmethodID PRCODEMethodID;
 
 static jmethodID R_ToplevelExecMethodID;
 static jmethodID restoreHandlerStacksMethodID;
@@ -132,6 +137,7 @@ static jmethodID Rf_ncolsMethodID;
 
 static jclass CharSXPWrapperClass;
 static jfieldID CharSXPWrapperContentsFieldID;
+jclass JNIUpCallsRFFIImplClass;
 
 jmethodID setCompleteMethodID;
 
@@ -151,24 +157,24 @@ void init_internals(JNIEnv *env) {
 	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_installMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_install", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	Rf_warningMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warning", "(Ljava/lang/Object;)V", 0);
+	Rf_warningcallMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warningcall", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0);
+	Rf_errorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_error", "(Ljava/lang/Object;)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);
+	R_NewHashedEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;I)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);
+	RprintfMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rprintf", "(Ljava/lang/Object;)V", 0);
+	R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_MAKE_CLASS", "(Ljava/lang/Object;)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_inheritsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_inherits", "(Ljava/lang/Object;Ljava/lang/Object;)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);
@@ -195,9 +201,10 @@ void init_internals(JNIEnv *env) {
 	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_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_mkCharLenCEMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_mkCharLenCE", "(Ljava/lang/Object;II)Ljava/lang/Object;", 0);
+        Rf_coerceVectorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_coerceVector", "(Ljava/lang/Object;I)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);
@@ -205,8 +212,7 @@ void init_internals(JNIEnv *env) {
 	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);
+	IS_S4_OBJECTMethodID = checkGetMethodID(env, UpCallsRFFIClass, "IS_S4_OBJECT", "(Ljava/lang/Object;)I", 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);
@@ -215,9 +221,12 @@ void init_internals(JNIEnv *env) {
 	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);
+	PRSEENMethodID = checkGetMethodID(env, UpCallsRFFIClass, "PRSEEN", "(Ljava/lang/Object;)I", 0);
+	PRENVMethodID = checkGetMethodID(env, UpCallsRFFIClass, "PRENV", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	R_PromiseExprMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_PromiseExpr", "(Ljava/lang/Object;)Ljava/lang/Object;", 0);
+	PRCODEMethodID = checkGetMethodID(env, UpCallsRFFIClass, "PRCODE", "(Ljava/lang/Object;)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);
@@ -236,7 +245,11 @@ void init_internals(JNIEnv *env) {
     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, UpCallsRFFIClass, "setComplete", "(Ljava/lang/Object;Z)V", 0);
+    // static JNI-specific methods
+	JNIUpCallsRFFIImplClass = checkFindClass(env, "com/oracle/truffle/r/runtime/ffi/jni/JNIUpCallsRFFIImpl");
+	logNotCharSXPWrapperMethodID = checkGetMethodID(env, UpCallsRFFIClass, "logNotCharSXPWrapper", "(Ljava/lang/Object;)V", 1);
+	restoreHandlerStacksMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_ToplevelExecRestoreErrorHandlerStacks", "(Ljava/lang/Object;)V", 1);
+    setCompleteMethodID = checkGetMethodID(env, UpCallsRFFIClass, "setComplete", "(Ljava/lang/Object;Z)V", 1);
 }
 
 static jstring stringFromCharSXP(JNIEnv *thisenv, SEXP charsxp) {
@@ -244,7 +257,7 @@ static jstring stringFromCharSXP(JNIEnv *thisenv, SEXP charsxp) {
 	validateRef(thisenv, charsxp, "stringFromCharSXP");
 	if (!(*thisenv)->IsInstanceOf(thisenv, charsxp, CharSXPWrapperClass)) {
 
-	    (*thisenv)->CallVoidMethod(thisenv, UpCallsRFFIObject, logNotCharSXPWrapperMethodID, charsxp);
+	    (*thisenv)->CallStaticVoidMethod(thisenv, JNIUpCallsRFFIImplClass, logNotCharSXPWrapperMethodID, charsxp);
 	    fatalError("only CharSXPWrapper expected in stringFromCharSXP");
 	}
 #endif
@@ -527,7 +540,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)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_mkCharLenCEMethodID, bytes, (int) enc);
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_mkCharLenCEMethodID, bytes, len, (int) enc);
 	return checkRef(thisenv, result);
 }
 
@@ -1047,14 +1060,15 @@ void SET_HASHTAB(SEXP x, SEXP v) {
 	unimplemented("SET_HASHTAB");
 }
 
-
 SEXP PRCODE(SEXP x) {
-	return unimplemented("PRCODE");
+    JNIEnv *thisenv = getEnv();
+    return (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, PRCODEMethodID, x);
 }
 
 SEXP PRENV(SEXP x) {
-	unimplemented("PRSEEN");
-    return 0;
+    JNIEnv *thisenv = getEnv();
+    SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, PRENVMethodID, x);
+    return checkRef(thisenv, result);
 }
 
 SEXP PRVALUE(SEXP x) {
@@ -1064,7 +1078,8 @@ SEXP PRVALUE(SEXP x) {
 }
 
 int PRSEEN(SEXP x) {
-	return (int) unimplemented("PRSEEN");
+    JNIEnv *thisenv = getEnv();
+    return (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, PRSEENMethodID, x);
 }
 
 void SET_PRSEEN(SEXP x, int v) {
@@ -1217,6 +1232,13 @@ SEXP Rf_asChar(SEXP x){
 	return checkRef(thisenv, result);
 }
 
+SEXP Rf_coerceVector(SEXP x, SEXPTYPE mode){
+	TRACE(TARGp, x);
+	JNIEnv *thisenv = getEnv();
+	SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_coerceVectorMethodID, x, mode);
+	return checkRef(thisenv, result);
+}
+
 SEXP Rf_PairToVectorList(SEXP x){
 	TRACE(TARGp, x);
 	JNIEnv *thisenv = getEnv();
@@ -1246,11 +1268,11 @@ int Rf_asInteger(SEXP x) {
 	return (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_asIntegerMethodID, x);
 }
 
-//double Rf_asReal(SEXP x) {
-//	TRACE(TARGp, x);
-//	JNIEnv *thisenv = getEnv();
-//	return (*thisenv)->CallDoubleMethod(thisenv, UpCallsRFFIObject, Rf_asRealMethodID, x);
-//}
+double Rf_asReal(SEXP x) {
+	TRACE(TARGp, x);
+	JNIEnv *thisenv = getEnv();
+	return (*thisenv)->CallDoubleMethod(thisenv, UpCallsRFFIObject, Rf_asRealMethodID, x);
+}
 
 Rcomplex Rf_asComplex(SEXP x){
 	unimplemented("Rf_asLogical");
@@ -1367,7 +1389,7 @@ R_len_t R_BadLongVector(SEXP x, const char *y, int z) {
 
 int IS_S4_OBJECT(SEXP x) {
 	JNIEnv *env = getEnv();
-	return 	(*env)->CallIntMethod(env, UpCallsRFFIObject, isS4ObjectMethodID, x);
+	return 	(*env)->CallIntMethod(env, UpCallsRFFIObject, IS_S4_OBJECTMethodID, x);
 }
 
 void SET_S4_OBJECT(SEXP x) {
@@ -1381,7 +1403,7 @@ Rboolean R_ToplevelExec(void (*fun)(void *), void *data) {
 	JNIEnv *env = getEnv();
 	jobject handlerStacks = (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_ToplevelExecMethodID);
 	fun(data);
-	(*env)->CallVoidMethod(env, UpCallsRFFIObject, restoreHandlerStacksMethodID, handlerStacks);
+	(*env)->CallStaticVoidMethod(env, JNIUpCallsRFFIImplClass, restoreHandlerStacksMethodID, handlerStacks);
 	// TODO how do we detect error
 	return TRUE;
 }
@@ -1494,7 +1516,8 @@ double R_strtod(const char *c, char **end) {
 }
 
 SEXP R_PromiseExpr(SEXP x) {
-	return unimplemented("R_PromiseExpr");
+    JNIEnv *thisenv = getEnv();
+    return (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, R_PromiseExprMethodID, x);
 }
 
 SEXP R_ClosureExpr(SEXP x) {
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 eb81606672d73f8a5cfee40801ca109e6ce7e0c0..4ec83f1392613e02ef7b74b0b7a44aba2e34dd37 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1249,13 +1249,5 @@ Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Call_callVoid0(JNIEnv *env, jclas
 	callExit(env);
 }
 
-#include <Rinterface.h>
-
-JNIEXPORT void JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1Call_nativeSetInteractive(JNIEnv *env, jclass c, jboolean interactive) {
-	R_Interactive = interactive;
-}
-
-
 
 
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 2ab54e4fda0141f22c8e2d6d34313e63cd8798d8..03118d01c25eaf42c879226e0dfadf0a4476489a 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -332,7 +332,7 @@ static void releaseNativeArray(JNIEnv *env, int i, int freedata) {
 			fatalError("releaseNativeArray type");
 		}
 		// update complete status
-		(*env)->CallVoidMethod(env, UpCallsRFFIObject, setCompleteMethodID, cv.obj, complete);
+		(*env)->CallStaticVoidMethod(env, JNIUpCallsRFFIImplClass, setCompleteMethodID, cv.obj, complete);
 
         if (freedata) {
             // free up the slot
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 99732f93766987fdceb40035a84eacce6111d882..c86fc4bc15d69e15f9cb22bc70ced2a0d96676ad 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -91,6 +91,7 @@ void setEmbedded(void);
 void setTempDir(JNIEnv *, jstring tempDir);
 
 extern jclass UpCallsRFFIClass;
+extern jclass JNIUpCallsRFFIImplClass;
 extern jobject UpCallsRFFIObject;
 extern FILE *traceFile;
 
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 10fb96f8e8134669890a83683a9fe6677e5b8c38..cbab66f68fde80d60e08d77d7956910c89d45001 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/variables.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/variables.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,32 +29,106 @@
 #include <jni.h>
 #include <Rinterface.h>
 #include <rffiutils.h>
-#include <variable_defs.h>
 
 jmethodID R_GlobalEnvMethodID;
 jmethodID R_BaseEnvMethodID;
 jmethodID R_BaseNamespaceMethodID;
 jmethodID R_NamespaceRegistryMethodID;
-jmethodID isInteractiveMethodID;
+jmethodID R_InteractiveMethodID;
 jmethodID R_GlobalContextMethodID;
 
+// The variables have been rewritten as functions in Rinternals.h
+// Apart from those that are RContext specific in FastR, the rest are
+// stored here as JNI globals refs.
+
+static SEXP R_EmptyEnv_static;
+static SEXP R_Srcref_static;
+static SEXP R_NilValue_static;
+static SEXP R_UnboundValue_static;
+static SEXP R_MissingArg_static;
+static SEXP R_BaseSymbol_static;
+static SEXP R_Bracket2Symbol_static;   /* "[[" */
+static SEXP R_BracketSymbol_static;    /* "[" */
+static SEXP R_BraceSymbol_static;      /* "{" */
+static SEXP R_ClassSymbol_static;     /* "class" */
+static SEXP R_DeviceSymbol_static;     /* ".Device" */
+static SEXP R_DevicesSymbol_static;     /* ".Devices" */
+static SEXP R_DimNamesSymbol_static;   /* "dimnames" */
+static SEXP R_DimSymbol_static;     /* "dim" */
+static SEXP R_DollarSymbol_static;     /* "$" */
+static SEXP R_DotsSymbol_static;     /* "..." */
+static SEXP R_DropSymbol_static;     /* "drop" */
+static SEXP R_LastvalueSymbol_static;  /* ".Last.value" */
+static SEXP R_LevelsSymbol_static;     /* "levels" */
+static SEXP R_ModeSymbol_static;     /* "mode" */
+static SEXP R_NameSymbol_static;     /* "name" */
+static SEXP R_NamesSymbol_static;     /* "names" */
+static SEXP R_NaRmSymbol_static;     /* "na.rm" */
+static SEXP R_PackageSymbol_static;    /* "package" */
+static SEXP R_QuoteSymbol_static;     /* "quote" */
+static SEXP R_RowNamesSymbol_static;   /* "row.names" */
+static SEXP R_SeedsSymbol_static;     /* ".Random.seed" */
+static SEXP R_SourceSymbol_static;     /* "source" */
+static SEXP R_TspSymbol_static;     /* "tsp" */
+static SEXP R_dot_defined_static;      /* ".defined" */
+static SEXP R_dot_Method_static;       /* ".Method" */
+static SEXP R_dot_target_static;       /* ".target" */
+static SEXP R_NaString_static;	    /* NA_STRING as a CHARSXP */
+static SEXP R_BlankString_static;	    /* "" as a CHARSXP */
+static SEXP R_BlankScalarString_static;	    /* "" as a STRSXP */
+static SEXP	R_NamespaceEnvSymbol_static;   // ".__NAMESPACE__."
+
+// Symbols not part of public API but used in FastR tools implementation
+static SEXP R_SrcrefSymbol_static;
+static SEXP R_SrcfileSymbol_static;
+static SEXP R_RestartToken_static;
+
+static const char *R_Home_static;
+static const char *R_TempDir_static;
+
+// Arith.h
+double R_NaN;		/* IEEE NaN */
+double R_PosInf;	/* IEEE Inf */
+double R_NegInf;	/* IEEE -Inf */
+double R_NaReal;	/* NA_REAL: IEEE */
+int R_NaInt;	/* NA_INTEGER:= INT_MIN currently */
+
+// various ignored flags and variables nevertheless needed to resolve symbols
+Rboolean R_Visible;
+Rboolean R_interrupts_suspended;
+int R_interrupts_pending;
+Rboolean mbcslocale;
+Rboolean useaqua;
+char* OutDec = ".";
+Rboolean utf8locale = FALSE;
+Rboolean mbcslocale = FALSE;
+Rboolean latin1locale = FALSE;
+int R_dec_min_exponent = -308;
+int max_contour_segments = 25000;
+
+// from sys-std.c
+#include <R_ext/eventloop.h>
+
+static InputHandler BasicInputHandler = {2, -1, NULL};
+InputHandler *R_InputHandlers = &BasicInputHandler;
+
 // R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
-SEXP FASTR_GlobalEnv() {
+SEXP FASTR_R_GlobalEnv() {
 	JNIEnv *env = getEnv();
 	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_GlobalEnvMethodID);
 }
 
-SEXP FASTR_BaseEnv() {
+SEXP FASTR_R_BaseEnv() {
 	JNIEnv *env = getEnv();
 	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_BaseEnvMethodID);
 }
 
-SEXP FASTR_BaseNamespace() {
+SEXP FASTR_R_BaseNamespace() {
 	JNIEnv *env = getEnv();
 	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_BaseNamespaceMethodID);
 }
 
-SEXP FASTR_NamespaceRegistry() {
+SEXP FASTR_R_NamespaceRegistry() {
 	JNIEnv *env = getEnv();
 	return (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_NamespaceRegistryMethodID);
 }
@@ -65,22 +139,177 @@ CTXT FASTR_GlobalContext() {
     return addGlobalRef(env, res, 0);
 }
 
-static const char *R_Home_local;
-static void *R_NilValue_local;
-static void *R_UnboundValue_local;
-
 char *FASTR_R_Home() {
-	return (char *)R_Home_local;
+	return (char *) R_Home_static;
+}
+
+char *FASTR_R_TempDir() {
+	return (char *) R_TempDir_static;
+}
+
+Rboolean FASTR_R_Interactive() {
+	JNIEnv *env = getEnv();
+	CTXT res = (*env)->CallObjectMethod(env, UpCallsRFFIObject, R_InteractiveMethodID);
+}
+
+SEXP FASTR_R_EmptyEnv() {
+    return R_EmptyEnv_static;
+}
+
+SEXP FASTR_R_Srcref() {
+    return R_Srcref_static;
 }
 
 SEXP FASTR_R_NilValue() {
-	return R_NilValue_local;
+    return R_NilValue_static;
 }
 
 SEXP FASTR_R_UnboundValue() {
-	return R_UnboundValue_local;
+    return R_UnboundValue_static;
+}
+
+SEXP FASTR_R_MissingArg() {
+    return R_MissingArg_static;
+}
+
+SEXP FASTR_R_BaseSymbol() {
+    return R_BaseSymbol_static;
+}
+
+
+SEXP FASTR_R_BraceSymbol() {
+    return R_BraceSymbol_static;
+}
+
+SEXP FASTR_R_Bracket2Symbol() {
+    return R_Bracket2Symbol_static;
+}
+
+SEXP FASTR_R_BracketSymbol() {
+    return R_BracketSymbol_static;
+}
+
+SEXP FASTR_R_ClassSymbol() {
+    return R_ClassSymbol_static;
+}
+
+SEXP FASTR_R_DimNamesSymbol() {
+    return R_DimNamesSymbol_static;
+}
+
+SEXP FASTR_R_DimSymbol() {
+    return R_DimSymbol_static;
+}
+
+
+SEXP FASTR_R_DollarSymbol() {
+    return R_DollarSymbol_static;
+}
+
+SEXP FASTR_R_DotsSymbol() {
+    return R_DotsSymbol_static;
+}
+
+
+SEXP FASTR_R_DropSymbol() {
+    return R_DropSymbol_static;
+}
+
+SEXP FASTR_R_LastvalueSymbol() {
+    return R_LastvalueSymbol_static;
+}
+
+
+SEXP FASTR_R_LevelsSymbol() {
+    return R_LevelsSymbol_static;
+}
+
+SEXP FASTR_R_ModeSymbol() {
+    return R_ModeSymbol_static;
+}
+
+SEXP FASTR_R_NaRmSymbol() {
+    return R_NaRmSymbol_static;
+}
+
+
+SEXP FASTR_R_NameSymbol() {
+    return R_NameSymbol_static;
+}
+
+SEXP FASTR_R_NamesSymbol() {
+    return R_NamesSymbol_static;
+}
+
+
+SEXP FASTR_R_NamespaceEnvSymbol() {
+    return R_NamespaceEnvSymbol_static;
+}
+
+SEXP FASTR_R_PackageSymbol() {
+    return R_PackageSymbol_static;
+}
+
+SEXP FASTR_R_QuoteSymbol() {
+    return R_QuoteSymbol_static;
+}
+
+SEXP FASTR_R_RowNamesSymbol() {
+    return R_RowNamesSymbol_static;
+}
+
+SEXP FASTR_R_SeedsSymbol() {
+    return R_SeedsSymbol_static;
 }
 
+SEXP FASTR_R_SourceSymbol() {
+    return R_SourceSymbol_static;
+}
+
+SEXP FASTR_R_TspSymbol() {
+    return R_TspSymbol_static;
+}
+
+SEXP FASTR_R_dot_defined() {
+    return R_dot_defined_static;
+}
+
+SEXP FASTR_R_dot_Method() {
+    return R_dot_Method_static;
+}
+
+SEXP FASTR_R_dot_target() {
+    return R_dot_target_static;
+}
+
+SEXP FASTR_R_NaString() {
+    return R_NaString_static;
+}
+
+
+SEXP FASTR_R_BlankString() {
+    return R_BlankString_static;
+}
+
+SEXP FASTR_R_BlankScalarString() {
+    return R_BlankScalarString_static;
+}
+
+SEXP FASTR_R_DevicesSymbol() {
+    return R_DevicesSymbol_static;
+}
+
+SEXP FASTR_R_DeviceSymbol() {
+    return R_DeviceSymbol_static;
+}
+
+SEXP FASTR_R_SrcrefSymbol() {
+    return R_SrcrefSymbol_static;
+}
+
+SEXP FASTR_R_SrcfileSymbol() {
+    return R_SrcfileSymbol_static;
+}
 
 void init_variables(JNIEnv *env, jobjectArray initialValues) {
 	// initialValues is an array of enums
@@ -98,7 +327,7 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) {
 	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_InteractiveMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_Interactive", "()I", 0);
 	R_GlobalContextMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_GlobalContext", "()Ljava/lang/Object;", 0);
 
 	int length = (*env)->GetArrayLength(env, initialValues);
@@ -110,7 +339,7 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) {
 		jobject value = (*env)->CallObjectMethod(env, variable, getValueMethodID);
 		if (value != NULL) {
 			if (strcmp(nameChars, "R_Home") == 0) {
-				R_Home_local = (*env)->GetStringUTFChars(env, value, NULL);
+				R_Home_static = (*env)->GetStringUTFChars(env, value, NULL);
 			} else if (strcmp(nameChars, "R_NaN") == 0) {
 				R_NaN = (*env)->CallDoubleMethod(env, value, doubleValueMethodID);
 			} else if (strcmp(nameChars, "R_PosInf") == 0) {
@@ -121,86 +350,88 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) {
 				R_NaReal = (*env)->CallDoubleMethod(env, value, doubleValueMethodID);
 			} else if (strcmp(nameChars, "R_NaInt") == 0) {
 				R_NaInt = (*env)->CallIntMethod(env, value, intValueMethodID);
+			} else if (strcmp(nameChars, "R_TempDir") == 0) {
+				R_TempDir_static = (*env)->GetStringUTFChars(env, value, NULL);
 			} else {
 				SEXP ref = createGlobalRef(env, value, 1);
 				if (strcmp(nameChars, "R_EmptyEnv") == 0) {
-					R_EmptyEnv = ref;
+					R_EmptyEnv_static = ref;
 				} else if (strcmp(nameChars, "R_NilValue") == 0) {
-					R_NilValue_local = ref;
+					R_NilValue_static = ref;
 				} else if (strcmp(nameChars, "R_UnboundValue") == 0) {
-					R_UnboundValue_local = ref;
+					R_UnboundValue_static = ref;
 				} else if (strcmp(nameChars, "R_MissingArg") == 0) {
-					R_MissingArg = ref;
+					R_MissingArg_static = ref;
+				} else if (strcmp(nameChars, "R_BaseSymbol") == 0) {
+					R_BaseSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_Bracket2Symbol") == 0) {
-					R_Bracket2Symbol = ref;
+					R_Bracket2Symbol_static = ref;
 				} else if (strcmp(nameChars, "R_BracketSymbol") == 0) {
-					R_BracketSymbol = ref;
+					R_BracketSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_BraceSymbol") == 0) {
-					R_BraceSymbol = ref;
+					R_BraceSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_ClassSymbol") == 0) {
-					R_ClassSymbol = ref;
+					R_ClassSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DeviceSymbol") == 0) {
-					R_DeviceSymbol = ref;
+					R_DeviceSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DevicesSymbol") == 0) {
-					R_DevicesSymbol = ref;
+					R_DevicesSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DimNamesSymbol") == 0) {
-					R_DimNamesSymbol = ref;
+					R_DimNamesSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DimSymbol") == 0) {
-					R_DimSymbol = ref;
+					R_DimSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DollarSymbol") == 0) {
-					R_DollarSymbol = ref;
+					R_DollarSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DotsSymbol") == 0) {
-					R_DotsSymbol = ref;
+					R_DotsSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DropSymbol") == 0) {
-					R_DropSymbol = ref;
+					R_DropSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_LastvalueSymbol") == 0) {
-					R_LastvalueSymbol = ref;
+					R_LastvalueSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_LevelsSymbol") == 0) {
-					R_LevelsSymbol = ref;
+					R_LevelsSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_ModeSymbol") == 0) {
-					R_ModeSymbol = ref;
+					R_ModeSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_NameSymbol") == 0) {
-					R_NameSymbol = ref;
+					R_NameSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_NamesSymbol") == 0) {
-					R_NamesSymbol = ref;
+					R_NamesSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_NaRmSymbol") == 0) {
-					R_NaRmSymbol = ref;
+					R_NaRmSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_PackageSymbol") == 0) {
-					R_PackageSymbol = ref;
+					R_PackageSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_QuoteSymbol") == 0) {
-					R_QuoteSymbol = ref;
+					R_QuoteSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_RowNamesSymbol") == 0) {
-					R_RowNamesSymbol = ref;
+					R_RowNamesSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_SeedsSymbol") == 0) {
-					R_SeedsSymbol = ref;
+					R_SeedsSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_SourceSymbol") == 0) {
-					R_SourceSymbol = ref;
+					R_SourceSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_TspSymbol") == 0) {
-					R_TspSymbol = ref;
+					R_TspSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_dot_defined") == 0) {
-					R_dot_defined = ref;
+					R_dot_defined_static = ref;
 				} else if (strcmp(nameChars, "R_dot_Method") == 0) {
-					R_dot_Method = ref;
+					R_dot_Method_static = ref;
 				} else if (strcmp(nameChars, "R_dot_target") == 0) {
-					R_dot_target = ref;
+					R_dot_target_static = ref;
 				} else if (strcmp(nameChars, "R_SrcfileSymbol") == 0) {
-					R_SrcfileSymbol = ref;
+					R_SrcfileSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_SrcrefSymbol") == 0) {
-					R_SrcrefSymbol = ref;
+					R_SrcrefSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DimSymbol") == 0) {
-					R_DimSymbol = ref;
+					R_DimSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_DimNamesSymbol") == 0) {
-					R_DimNamesSymbol = ref;
+					R_DimNamesSymbol_static = ref;
 				} else if (strcmp(nameChars, "R_NaString") == 0) {
-					R_NaString = ref;
+					R_NaString_static = ref;
 				} else if (strcmp(nameChars, "R_BlankString") == 0) {
-					R_BlankString = ref;
-				} else if (strcmp(nameChars, "R_TrueValue") == 0) {
-				    R_TrueValue = ref;
-				} else if (strcmp(nameChars, "R_FalseValue") == 0) {
-				    R_FalseValue = ref;
-				} else if (strcmp(nameChars, "R_LogicalNAValue") == 0) {
-				    R_LogicalNAValue = ref;
+					R_BlankString_static = ref;
+				} else if (strcmp(nameChars, "R_BlankScalarString") == 0) {
+					R_BlankScalarString_static = ref;
+				} else if (strcmp(nameChars, "R_NamespaceEnvSymbol") == 0) {
+					R_NamespaceEnvSymbol_static = ref;
 				} else {
 					char msg[128];
 					strcpy(msg, "non-null R variable not assigned: ");
@@ -212,7 +443,3 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) {
 	}
 }
 
-void setTempDir(JNIEnv *env, jstring tempDir) {
-	R_TempDir = (*env)->GetStringUTFChars(env, tempDir, NULL);
-}
-
diff --git a/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c b/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c
index 22aab408ee0576d4ec8e32674505e01acdc169fe..fb7783eb30615359e3632ba3c9ddc86300a9fad2 100644
--- a/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c
+++ b/com.oracle.truffle.r.native/fficall/src/jniboot/jniboot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,23 +27,11 @@
 #include <dlfcn.h>
 #include <jni.h>
 
-// It seems that an internal (JVM) dlsym call can occur between a call to these functions and dlerror
-// (probably resolving the JNI dlerror symbol, so we capture it here (N.B. depends on single
-// threaded limitation).
+static jclass unsatisfiedLinkError;
 
-static jobject last_dlerror = NULL;
-
-static void create_dlerror_string(JNIEnv *env) {
-	if (last_dlerror != NULL) {
-		(*env)->DeleteGlobalRef(env, last_dlerror);
-		last_dlerror = NULL;
-	}
-	char *err = dlerror();
-	if (err == NULL) {
-		last_dlerror = NULL;
-	} else {
-//    	printf("dlerror: %s\n", err);
-		last_dlerror = (*env)->NewGlobalRef(env, (*env)->NewStringUTF(env, err));
+static void initUnsatisfiedLinkError(JNIEnv *env) {
+	if (unsatisfiedLinkError == NULL) {
+		unsatisfiedLinkError = (jclass) (*env)->NewGlobalRef(env, (*env)->FindClass(env, "java/lang/UnsatisfiedLinkError"));
 	}
 }
 
@@ -53,7 +41,10 @@ Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlopen(JNIEnv *env, j
     int flags = (local ? RTLD_LOCAL : RTLD_GLOBAL) | (now ? RTLD_NOW : RTLD_LAZY);
     void *handle = dlopen(path, flags);
     if (handle == NULL) {
-        create_dlerror_string(env);
+    	char *err = dlerror();
+    	initUnsatisfiedLinkError(env);
+    	// N.B.throw doesn't happen until return, so path is released
+    	(*env)->ThrowNew(env, unsatisfiedLinkError, err);
     }
     (*env)->ReleaseStringUTFChars(env, jpath, path);
     return (jlong) handle;
@@ -63,7 +54,14 @@ JNIEXPORT jlong JNICALL
 Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlsym(JNIEnv *env, jclass c, jlong handle, jstring jsymbol) {
     const char *symbol = (*env)->GetStringUTFChars(env, jsymbol, NULL);
     void *address = dlsym((void *)handle, symbol);
-    create_dlerror_string(env);
+    if (address == NULL) {
+    	char *err = dlerror();
+    	if (err != NULL) {
+        	initUnsatisfiedLinkError(env);
+        	// N.B.throw doesn't happen until return, so symbol is released
+        	(*env)->ThrowNew(env, unsatisfiedLinkError, err);
+    	}
+    }
     (*env)->ReleaseStringUTFChars(env, jsymbol, symbol);
     return (jlong) address;
 }
@@ -74,8 +72,4 @@ Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlclose(JNIEnv *env,
     return rc;
 }
 
-JNIEXPORT jobject JNICALL
-Java_com_oracle_truffle_r_runtime_ffi_jni_JNI_1DLL_native_1dlerror(JNIEnv *env, jclass c) {
-   	return last_dlerror;
-}
 
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/variables.c b/com.oracle.truffle.r.native/fficall/src/truffle/variables.c
deleted file mode 100644
index a9944e5183845b3407a18815dc52638b53caa09f..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/fficall/src/truffle/variables.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.
- */
-#include <rffiutils.h>
-#include <variable_defs.h>
-
-// R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
-SEXP FASTR_GlobalEnv() {
-	IMPORT_CALLHELPER();
-	return truffle_invoke(obj, "R_GlobalEnv");
-}
-
-SEXP FASTR_BaseEnv() {
-	IMPORT_CALLHELPER();
-	return truffle_invoke(obj, "R_BaseEnv");
-}
-
-SEXP FASTR_BaseNamespace() {
-	IMPORT_CALLHELPER();
-	return truffle_invoke(obj, "R_BaseNamespace");
-}
-
-SEXP FASTR_NamespaceRegistry() {
-	IMPORT_CALLHELPER();
-	return truffle_invoke(obj, "R_NamespaceRegistry");
-}
-
-Rboolean FASTR_IsInteractive() {
-	IMPORT_CALLHELPER();
-	return (Rboolean) truffle_invoke_i(obj, "isInteractive");
-}
-
-char *FASTR_R_Home() {
-	IMPORT_CALLHELPER();
-	return (char *) truffle_invoke(obj, "R_Home");
-}
-
-SEXP FASTR_R_NilValue() {
-	IMPORT_CALLHELPER();
-	return truffle_invoke(obj, "R_NilValue");
-
-}
-
-SEXP FASTR_R_UnboundValue() {
-	IMPORT_CALLHELPER();
-	return truffle_invoke(obj, "R_UnboundValue");
-}
-
-void Call_initvar_obj(int index, void* value) {
-	/*
-	switch (index) {
-    case R_Home_x: R_Home = (char *) value; break;
-    case R_TempDir_x: R_TempDir = value; break;
-    case R_NilValue_x: R_NilValue = value; break;
-    case R_UnboundValue_x: R_UnboundValue = value; break;
-    case R_MissingArg_x: R_MissingArg = value; break;
-    case R_Srcref_x: R_Srcref = value; break;
-    case R_Bracket2Symbol_x: R_Bracket2Symbol = value; break;
-    case R_BracketSymbol_x: R_BracketSymbol = value; break;
-    case R_BraceSymbol_x: R_BraceSymbol = value; break;
-    case R_ClassSymbol_x: R_ClassSymbol = value; break;
-    case R_DeviceSymbol_x: R_DeviceSymbol = value; break;
-    case R_DevicesSymbol_x: R_DevicesSymbol = value; break;
-    case R_DimNamesSymbol_x: R_DimNamesSymbol = value; break;
-    case R_DimSymbol_x: R_DimSymbol = value; break;
-    case R_DollarSymbol_x: R_DollarSymbol = value; break;
-    case R_DotsSymbol_x: R_DotsSymbol = value; break;
-    case R_DropSymbol_x: R_DropSymbol = value; break;
-    case R_LastvalueSymbol_x: R_LastvalueSymbol = value; break;
-    case R_LevelsSymbol_x: R_LevelsSymbol = value; break;
-    case R_ModeSymbol_x: R_ModeSymbol = value; break;
-    case R_NameSymbol_x: R_NameSymbol = value; break;
-    case R_NamesSymbol_x: R_NamesSymbol = value; break;
-    case R_NaRmSymbol_x: R_NaRmSymbol = value; break;
-    case R_PackageSymbol_x: R_PackageSymbol = value; break;
-    case R_QuoteSymbol_x: R_QuoteSymbol = value; break;
-    case R_RowNamesSymbol_x: R_RowNamesSymbol = value; break;
-    case R_SeedsSymbol_x: R_SeedsSymbol = value; break;
-    case R_SourceSymbol_x: R_SourceSymbol = value; break;
-    case R_TspSymbol_x: R_TspSymbol = value; break;
-    case R_dot_defined_x: R_dot_defined = value; break;
-    case R_dot_Method_x: R_dot_Method = value; break;
-    case R_dot_target_x: R_dot_target = value; break;
-    case R_SrcrefSymbol_x: R_SrcrefSymbol = value; break;
-    case R_SrcfileSymbol_x: R_SrcfileSymbol = value; break;
-    case R_NaString_x: R_NaString = value; break;
-    case R_NaInt_x: R_NaInt = (int) value; break;
-    case R_BlankString_x: R_BlankString = value; break;
-    case R_TrueValue_x: R_TrueValue = value; break;
-    case R_FalseValue_x: R_FalseValue = value; break;
-    case R_LogicalNAValue_x: R_LogicalNAValue = value; break;
-	}
-	*/
-}
-
-void Call_initvar_double(int index, double value) {
-	switch (index) {
-    case R_NaN_x: R_NaN = value; break;
-	}
-}
-
-void Call_initvar_int(int index, int value) {
-	switch (index) {
-    case R_NaInt_x: R_NaInt = value; break;
-    case R_PosInf_x: R_PosInf = value; break;
-    case R_NegInf_x: R_NegInf = value; break;
-    case R_NaReal_x: R_NaReal = value; break;
-	}
-}
-
-
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/Makefile b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Makefile
similarity index 98%
rename from com.oracle.truffle.r.native/fficall/src/truffle/Makefile
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/Makefile
index f493f5f594d809918fe148e508e6384ae39e9fcb..99821495d2e45ace8ec7db91c0034b62688c4f92 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle/Makefile
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/README.md b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/README.md
similarity index 100%
rename from com.oracle.truffle.r.native/fficall/src/truffle/README.md
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/README.md
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/Rdynload_fastr.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rdynload_fastr.c
similarity index 98%
rename from com.oracle.truffle.r.native/fficall/src/truffle/Rdynload_fastr.c
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rdynload_fastr.c
index 45eef643d9a124db2d32f59496e422faaf3387a7..5898757681b0d2fce70c0ae8b228210c281684a8 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle/Rdynload_fastr.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rdynload_fastr.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rinternals.c
similarity index 99%
rename from com.oracle.truffle.r.native/fficall/src/truffle/Rinternals.c
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rinternals.c
index d91c866eb705a11d63e948c03a24cfe4d61949f6..db953ec45718afe03c0a084dbe838bc399c77bd2 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle/Rinternals.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rinternals.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -715,7 +715,7 @@ SEXP PRCODE(SEXP x) {
 }
 
 SEXP PRENV(SEXP x) {
-	unimplemented("PRSEEN");
+	unimplemented("PRENV");
     return 0;
 }
 
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/caccess.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/caccess.c
similarity index 95%
rename from com.oracle.truffle.r.native/fficall/src/truffle/caccess.c
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/caccess.c
index d07c61c716cf948d2b91d97027a2aa67c0e4b9cc..6743e91b48a8436d2f36d0ae9f41da0926747e0a 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle/caccess.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/caccess.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/llvm_dummy.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.c
similarity index 94%
rename from com.oracle.truffle.r.native/fficall/src/truffle/llvm_dummy.c
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.c
index f786ab945c7932692e6fbecf8c98b9e0b58bac95..4ad1b6b8d8df5d22e2431a5652d1a4fbfe42b8f8 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle/llvm_dummy.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/llvm_dummy.f b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.f
similarity index 100%
rename from com.oracle.truffle.r.native/fficall/src/truffle/llvm_dummy.f
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.f
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/rffiutils.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/rffiutils.c
similarity index 95%
rename from com.oracle.truffle.r.native/fficall/src/truffle/rffiutils.c
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/rffiutils.c
index 82a74a54059453e7fc5731fc9c429b7a8f3949c4..bc39a9ebed13c9b4c21b54f6558f4231ee1a6813 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/rffiutils.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle/rffiutils.h b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/rffiutils.h
similarity index 95%
rename from com.oracle.truffle.r.native/fficall/src/truffle/rffiutils.h
rename to com.oracle.truffle.r.native/fficall/src/truffle_llvm/rffiutils.h
index d4a21793b398c4e34ea2c64f83deac513ec88ba4..2a380ccc847e663f248294608b6566ddf88e9d21 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/rffiutils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/variables.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/variables.c
new file mode 100644
index 0000000000000000000000000000000000000000..f41cc549341b79624a2dcb02fff13a97918baef8
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/variables.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#include <rffiutils.h>
+#include <variables.h>
+
+// Arith.h
+double R_NaN;		/* IEEE NaN */
+double R_PosInf;	/* IEEE Inf */
+double R_NegInf;	/* IEEE -Inf */
+double R_NaReal;	/* NA_REAL: IEEE */
+int R_NaInt;	/* NA_INTEGER:= INT_MIN currently */
+
+// R_GlobalEnv et al are not a variables in FASTR as they are RContext specific
+SEXP FASTR_R_GlobalEnv() {
+	IMPORT_CALLHELPER();
+	return truffle_invoke(obj, "R_GlobalEnv");
+}
+
+SEXP FASTR_R_BaseEnv() {
+	IMPORT_CALLHELPER();
+	return truffle_invoke(obj, "R_BaseEnv");
+}
+
+SEXP FASTR_R_BaseNamespace() {
+	IMPORT_CALLHELPER();
+	return truffle_invoke(obj, "R_BaseNamespace");
+}
+
+SEXP FASTR_R_NamespaceRegistry() {
+	IMPORT_CALLHELPER();
+	return truffle_invoke(obj, "R_NamespaceRegistry");
+}
+
+Rboolean FASTR_R_Interactive() {
+	IMPORT_CALLHELPER();
+	return (Rboolean) truffle_invoke_i(obj, "R_Interactive");
+}
+
+char *FASTR_R_Home() {
+	IMPORT_CALLHELPER();
+	return (char *) truffle_invoke(obj, "R_Home");
+}
+
+// Callbacks because cannot store TruffleObjects in memory (currently)
+
+SEXP FASTR_R_NilValue() {
+	IMPORT_CALLHELPER();
+	return truffle_invoke(obj, "R_NilValue");
+
+}
+
+SEXP FASTR_R_UnboundValue() {
+	IMPORT_CALLHELPER();
+	return truffle_invoke(obj, "R_UnboundValue");
+}
+
+SEXP FASTR_R_EmptyEnv() {
+	IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_EmptyEnv");
+}
+
+SEXP FASTR_R_MissingArg() {
+    IMPORT_CALLHELPER();
+    return Truffle_Invoke(Obj, "R_MissingArg");
+}
+
+SEXP FASTR_R_BaseSymbol() {
+    IMPORT_CALLHELPER();
+    Return Truffle_Invoke(Obj, "R_BaseSymbol");
+}
+
+SEXP FASTR_R_BraceSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_BraceSymbol");
+}
+
+SEXP FASTR_R_Bracket2Symbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_Bracket2Symbol");
+}
+
+SEXP FASTR_R_BracketSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_BracketSymbol");
+}
+
+SEXP FASTR_R_ClassSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_ClassSymbol");
+}
+
+SEXP FASTR_R_DeviceSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_DeviceSymbol");
+}
+
+SEXP FASTR_R_DimNamesSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_DimNamesSymbol");
+}
+
+SEXP FASTR_R_DimSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_DimSymbol");
+}
+
+SEXP FASTR_R_DollarSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_DollarSymbol");
+}
+
+SEXP FASTR_R_DotsSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_DotsSymbol");
+}
+
+SEXP FASTR_R_DropSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_DropSymbol");
+}
+
+SEXP FASTR_R_LastvalueSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_LastvalueSymbol");
+}
+
+SEXP FASTR_R_LevelsSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_LevelsSymbol");
+}
+
+SEXP FASTR_R_ModeSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_ModeSymbol");
+}
+
+SEXP FASTR_R_NaRmSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_NaRmSymbol");
+}
+
+SEXP FASTR_R_NameSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_NameSymbol");
+}
+
+SEXP FASTR_R_NamesSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_NamesSymbol");
+}
+
+SEXP FASTR_R_NamespaceEnvSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_NamespaceEnvSymbol");
+}
+
+SEXP FASTR_R_PackageSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_PackageSymbol");
+}
+
+SEXP FASTR_R_QuoteSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_QuoteSymbol");
+}
+
+SEXP FASTR_R_RowNamesSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_RowNamesSymbol");
+}
+
+SEXP FASTR_R_SeedsSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_SeedsSymbol");
+}
+
+SEXP FASTR_R_SourceSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_SourceSymbol");
+}
+
+SEXP FASTR_R_TspSymbol() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_TspSymbol");
+}
+
+SEXP FASTR_R_dot_defined() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_dot_defined");
+}
+
+SEXP FASTR_R_dot_Method() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_dot_Method");
+}
+
+SEXP FASTR_R_dot_target() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_dot_target");
+}
+
+SEXP FASTR_R_NaString() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_NaString");
+}
+
+SEXP FASTR_R_BlankString() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_BlankString");
+}
+
+SEXP FASTR_R_BlankScalarString() {
+    IMPORT_CALLHELPER();
+    return truffle_invoke(obj, "R_BlankScalarString");
+}
+
+
+void Call_initvar_double(int index, double value) {
+	switch (index) {
+    case R_NaN_x: R_NaN = value; break;
+	}
+}
+
+void Call_initvar_int(int index, int value) {
+	switch (index) {
+    case R_NaInt_x: R_NaInt = value; break;
+    case R_PosInf_x: R_PosInf = value; break;
+    case R_NegInf_x: R_NegInf = value; break;
+    case R_NaReal_x: R_NaReal = value; break;
+	}
+}
+
+
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/variables.h b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/variables.h
new file mode 100644
index 0000000000000000000000000000000000000000..3a245b1fa929a70ebea8719ae90c36704da0bc17
--- /dev/null
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/variables.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+#define R_Home_x 0
+#define R_TempDir_x 1
+#define R_NilValue_x 2
+#define R_UnboundValue_x 3
+#define R_MissingArg_x 4
+#define R_GlobalEnv_x 5
+#define R_EmptyEnv_x 6
+#define R_BaseEnv_x 7
+#define R_BaseNamespace_x 8
+#define R_NamespaceRegistry_x 9
+#define R_Srcref_x 10
+#define R_Bracket2Symbol_x 11
+#define R_BracketSymbol_x 12
+#define R_BraceSymbol_x 13
+#define R_ClassSymbol_x 14
+#define R_DeviceSymbol_x 15
+#define R_DevicesSymbol_x 16
+#define R_DimNamesSymbol_x 17
+#define R_DimSymbol_x 18
+#define R_DollarSymbol_x 19
+#define R_DotsSymbol_x 20
+#define R_DropSymbol_x 21
+#define R_LastvalueSymbol_x 22
+#define R_LevelsSymbol_x 23
+#define R_ModeSymbol_x 24
+#define R_NameSymbol_x 25
+#define R_NamesSymbol_x 26
+#define R_NaRmSymbol_x 27
+#define R_PackageSymbol_x 28
+#define R_QuoteSymbol_x 29
+#define R_RowNamesSymbol_x 30
+#define R_SeedsSymbol_x 31
+#define R_SourceSymbol_x 32
+#define R_TspSymbol_x 33
+#define R_dot_defined_x 34
+#define R_dot_Method_x 35
+#define R_dot_target_x 36
+#define R_SrcrefSymbol_x 37
+#define R_SrcfileSymbol_x 38
+#define R_NaString_x 39
+#define R_NaN_x 40
+#define R_PosInf_x 41
+#define R_NegInf_x 42
+#define R_NaReal_x 43
+#define R_NaInt_x 44
+#define R_BlankString_x 45
+#define R_BlankScalarString_x 46
+#define R_TrueValue_x 47
+#define R_FalseValue_x 48
+#define R_LogicalNAValue_x 49
+#define R_BaseSymbol_x 50
+#define R_NamespaceEnvSymbol_x 51
+#define R_RestartToken_x 52
diff --git a/com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h b/com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h
deleted file mode 100644
index b3c3831a5acd1392c93c3e207ebdd30ea9d16238..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h
+++ /dev/null
@@ -1,154 +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-2015, The R Core Team
- * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-
-// These are the definitions (i.e., not extern) that are defined as extern in RInternals.h.
-// They are in a a separate header to support a JNI and non-JNI implementation of their values.
-// Therefore this file must only be included by the implementation.
-// N.B. Some variables become functions in FastR, see RInternals.h
-
-/* Evaluation Environment */
-//SEXP R_GlobalEnv;
-SEXP R_EmptyEnv;
-//SEXP R_BaseEnv;
-//SEXP R_BaseNamespace;
-//SEXP R_NamespaceRegistry;
-
-//SEXP R_Srcref;
-
-/* Special Values */
-SEXP R_NilValue;
-SEXP R_UnboundValue;
-SEXP R_MissingArg;
-
-/* Symbol Table Shortcuts */
-SEXP R_Bracket2Symbol;   /* "[[" */
-SEXP R_BracketSymbol;    /* "[" */
-SEXP R_BraceSymbol;      /* "{" */
-SEXP R_ClassSymbol;     /* "class" */
-SEXP R_DeviceSymbol;     /* ".Device" */
-SEXP R_DevicesSymbol;     /* ".Devices" */
-SEXP R_DimNamesSymbol;   /* "dimnames" */
-SEXP R_DimSymbol;     /* "dim" */
-SEXP R_DollarSymbol;     /* "$" */
-SEXP R_DotsSymbol;     /* "..." */
-SEXP R_DropSymbol;     /* "drop" */
-SEXP R_LastvalueSymbol;  /* ".Last.value" */
-SEXP R_LevelsSymbol;     /* "levels" */
-SEXP R_ModeSymbol;     /* "mode" */
-SEXP R_NameSymbol;     /* "name" */
-SEXP R_NamesSymbol;     /* "names" */
-SEXP R_NaRmSymbol;     /* "na.rm" */
-SEXP R_PackageSymbol;    /* "package" */
-SEXP R_QuoteSymbol;     /* "quote" */
-SEXP R_RowNamesSymbol;   /* "row.names" */
-SEXP R_SeedsSymbol;     /* ".Random.seed" */
-SEXP R_SourceSymbol;     /* "source" */
-SEXP R_TspSymbol;     /* "tsp" */
-
-SEXP R_dot_defined;      /* ".defined" */
-SEXP R_dot_Method;       /* ".Method" */
-SEXP R_dot_target;       /* ".target" */
-SEXP R_NaString;	    /* NA_STRING as a CHARSXP */
-SEXP R_BlankString;	    /* "" as a CHARSXP */
-
-// Symbols not part of public API but used in FastR tools implementation
-SEXP R_SrcrefSymbol;
-SEXP R_SrcfileSymbol;
-
-// logical constants
-SEXP R_TrueValue;
-SEXP R_FalseValue;
-SEXP R_LogicalNAValue;
-
-// Arith.h
-double R_NaN;		/* IEEE NaN */
-double R_PosInf;	/* IEEE Inf */
-double R_NegInf;	/* IEEE -Inf */
-double R_NaReal;	/* NA_REAL: IEEE */
-int R_NaInt;	/* NA_INTEGER:= INT_MIN currently */
-
-// from Defn.h
-char* R_Home;
-const char* R_TempDir;
-
-// Set by a down call based on the setting in the initial context
-Rboolean R_Interactive;
-
-// various ignored flags and variables:
-Rboolean R_Visible;
-Rboolean R_interrupts_suspended;
-int R_interrupts_pending;
-Rboolean mbcslocale;
-Rboolean useaqua;
-char* OutDec = ".";
-Rboolean utf8locale = FALSE;
-Rboolean mbcslocale = FALSE;
-Rboolean latin1locale = FALSE;
-int R_dec_min_exponent = -308;
-int max_contour_segments = 25000;
-
-// from sys-std.c
-#include <R_ext/eventloop.h>
-
-static InputHandler BasicInputHandler = {2, -1, NULL};
-InputHandler *R_InputHandlers = &BasicInputHandler;
-
-// ordinal numbers of the RVariables enum
-#define R_Home_x 0
-#define R_TempDir_x 1
-#define R_NilValue_x 2
-#define R_UnboundValue_x 3
-#define R_MissingArg_x 4
-#define R_GlobalEnv_x 5
-#define R_EmptyEnv_x 6
-#define R_BaseEnv_x 7
-#define R_BaseNamespace_x 8
-#define R_NamespaceRegistry_x 9
-#define R_Srcref_x 10
-#define R_Bracket2Symbol_x 11
-#define R_BracketSymbol_x 12
-#define R_BraceSymbol_x 13
-#define R_ClassSymbol_x 14
-#define R_DeviceSymbol_x 15
-#define R_DevicesSymbol_x 16
-#define R_DimNamesSymbol_x 17
-#define R_DimSymbol_x 18
-#define R_DollarSymbol_x 19
-#define R_DotsSymbol_x 20
-#define R_DropSymbol_x 21
-#define R_LastvalueSymbol_x 22
-#define R_LevelsSymbol_x 23
-#define R_ModeSymbol_x 24
-#define R_NameSymbol_x 25
-#define R_NamesSymbol_x 26
-#define R_NaRmSymbol_x 27
-#define R_PackageSymbol_x 28
-#define R_QuoteSymbol_x 29
-#define R_RowNamesSymbol_x 30
-#define R_SeedsSymbol_x 31
-#define R_SourceSymbol_x 32
-#define R_TspSymbol_x 33
-#define R_dot_defined_x 34
-#define R_dot_Method_x 35
-#define R_dot_target_x 36
-#define R_SrcrefSymbol_x 37
-#define R_SrcfileSymbol_x 38
-#define R_NaString_x 39
-#define R_NaN_x 40
-#define R_PosInf_x 41
-#define R_NegInf_x 42
-#define R_NaReal_x 43
-#define R_NaInt_x 44
-#define R_BlankString_x 45
-#define R_TrueValue_x 46
-#define R_FalseValue_x 47
-#define R_LogicalNAValue_x 48
diff --git a/com.oracle.truffle.r.native/gnur/Makefile.gnur b/com.oracle.truffle.r.native/gnur/Makefile.gnur
index 4b9f8580e4a38070be7ed61503dd8c306926ca90..abc5c59b1227e8a21671fa957b3681d4588654a0 100644
--- a/com.oracle.truffle.r.native/gnur/Makefile.gnur
+++ b/com.oracle.truffle.r.native/gnur/Makefile.gnur
@@ -68,6 +68,10 @@ all: Makefile $(GNUR_HOME) iconv config build
 
 $(GNUR_HOME): 
 	tar xf $(TOPDIR)/../libdownloads/R-$(R_VERSION).tar.gz
+# Solaris doesn't need this and ed can't handle the size of the configure file!
+ifneq ($(OSNAME), SunOS)
+	ed $(GNUR_HOME)/configure < edconfigure # to fix the zlib version check (fixed in GNUR in the meantime)
+endif
 
 
 # After this platform check, GNUR_CONFIG_FLAGS must be set
diff --git a/com.oracle.truffle.r.native/gnur/edconfigure b/com.oracle.truffle.r.native/gnur/edconfigure
new file mode 100644
index 0000000000000000000000000000000000000000..ba5c8bbaf62383c3576331b6e809a59fff4e195e
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/edconfigure
@@ -0,0 +1,9 @@
+35510,35513c
+#ifdef ZLIB_VERNUM
+  if (ZLIB_VERNUM < 0x1250) {
+    exit(1);
+  }
+  exit(0);
+.
+w
+q
diff --git a/com.oracle.truffle.r.native/include/Makefile b/com.oracle.truffle.r.native/include/Makefile
index 5acbc6b49dc1a05ce37c7e19b4b2206bfe0803dd..2de8932ab170d53b33ed31cf7968e09cc26b3fbe 100644
--- a/com.oracle.truffle.r.native/include/Makefile
+++ b/com.oracle.truffle.r.native/include/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -44,14 +44,11 @@ R_HEADERS_TO_LINK := $(filter-out $(notdir $(R_HEADERS_LOCAL)),$(R_HEADERS_FILEN
 
 all: linked
 
-linked: ed_Rinternals ed_Rinterface_gcntx ed_Rinterface_interactive ed_GraphicsEngine
+linked:
 	mkdir -p R_ext
 	$(foreach file,$(R_HEADERS_TO_LINK),ln -sf $(GNUR_HOME)/include/$(file) $(file);)
 	ln -sf src/libintl.h
-	ed $(GNUR_HOME)/include/Rinternals.h < ed_Rinternals
-	ed $(GNUR_HOME)/include/Rinterface.h < ed_Rinterface_gcntx
-#	ed $(GNUR_HOME)/include/Rinterface.h < ed_Rinterface_interactive
-	ed $(GNUR_HOME)/include/R_ext/GraphicsEngine.h < ed_GraphicsEngine
+	mx edinclude $(GNUR_HOME)/include
 	$(foreach file,$(R_EXT_HEADERS_TO_LINK),ln -sf $(GNUR_HOME)/include/R_ext/$(file) R_ext/$(file);)
 #	cp $(R_EXT_HEADERS_LOCAL) R_ext
 	touch linked
diff --git a/com.oracle.truffle.r.native/include/ed_GraphicsEngine b/com.oracle.truffle.r.native/include/ed_GraphicsEngine
deleted file mode 100644
index 6481419d0997ef4eef4824fe5a7f785e3f3f761b..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/include/ed_GraphicsEngine
+++ /dev/null
@@ -1,3 +0,0 @@
-/MAX_GRAPHICS_SYSTEMS/
-s/24/256/
-w R_ext/GraphicsEngine.h
diff --git a/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx b/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx
deleted file mode 100644
index 88fe94a62a6d39d815458b68669f08a7f1c49529..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx
+++ /dev/null
@@ -1,23 +0,0 @@
-/R_GlobalContext/
-i
-#ifdef FASTR
-typedef void *CTXT;
-typedef void *SEXP;
-extern CTXT FASTR_GlobalContext();
-#define R_GlobalContext FASTR_GlobalContext()
-extern CTXT R_getGlobalFunctionContext();
-extern CTXT R_getParentFunctionContext(CTXT);
-extern SEXP R_getContextEnv(CTXT);
-extern SEXP R_getContextFun(CTXT);
-extern SEXP R_getContextCall(CTXT);
-extern SEXP R_getContextSrcRef(CTXT);
-extern int R_insideBrowser();
-extern int R_isGlobal(CTXT);
-extern int R_isEqual(void*, void*);
-#else
-.
-+1
-a
-#endif
-.
-w Rinterface.h
diff --git a/com.oracle.truffle.r.native/include/ed_Rinterface_interactive b/com.oracle.truffle.r.native/include/ed_Rinterface_interactive
deleted file mode 100644
index d226ba210788f9c015c03c6a495fd8c49b120d97..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/include/ed_Rinterface_interactive
+++ /dev/null
@@ -1,23 +0,0 @@
-/R_Interactive/
-i
-#ifdef FASTR
-LibExtern Rboolean FASTR_Interactive();
-#define R_Interactive FASTR_Interactive()
-#else
-.
-+1
-a
-#endif
-.
-/R_Home;/
-i
-#ifdef FASTR
-LibExtern char* FASTR_R_Home();
-#define R_Home FASTR_R_Home()
-#else
-.
-+1
-a
-#endif
-.
-w Rinterface.h
diff --git a/com.oracle.truffle.r.native/include/ed_Rinternals b/com.oracle.truffle.r.native/include/ed_Rinternals
deleted file mode 100644
index 11d0c1e55752a00ed78095033e28a3e1c6f7943a..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.native/include/ed_Rinternals
+++ /dev/null
@@ -1,114 +0,0 @@
-/USE_RINTERNALS section/
-i
-#ifdef FASTR
-// packages defining USE_INTERNALS expect certain defs (e.g. isNull) to be there
-#ifdef USE_RINTERNALS
-#define USE_RINTERNALS_DEFS
-#endif
-#undef USE_RINTERNALS
-#else
-.
-+1
-a
-#endif
-.
-/typedef struct SEXPREC \*SEXP;/
-i
-#ifdef FASTR
-typedef void *SEXP;
-#define DATAPTR(x)		R_DATAPTR(x)
-void *(R_DATAPTR)(SEXP x);
-#else
-.
-+1
-a
-#endif
-.
-/R_GlobalEnv/
-i
-#ifdef FASTR
-LibExtern SEXP FASTR_GlobalEnv();
-#define R_GlobalEnv FASTR_GlobalEnv()
-#else
-.
-+1
-a
-#endif
-.
-/R_BaseEnv/
-i
-#ifdef FASTR
-LibExtern SEXP FASTR_BaseEnv();
-#define R_BaseEnv FASTR_BaseEnv()
-#else
-.
-+1
-a
-#endif
-.
-/R_BaseNamespace/
-i
-#ifdef FASTR
-LibExtern SEXP FASTR_BaseNamespace();
-#define R_BaseNamespace FASTR_BaseNamespace()
-#else
-.
-+1
-a
-#endif
-.
-/R_NamespaceRegistry/
-i
-#ifdef FASTR
-LibExtern SEXP FASTR_NamespaceRegistry();
-#define R_NamespaceRegistry FASTR_NamespaceRegistry()
-#else
-.
-+1
-a
-#endif
-.
-/R_NilValue;/
-i
-#ifdef FASTR
-LibExtern SEXP FASTR_R_NilValue();
-#define R_NilValue FASTR_R_NilValue()
-#else
-.
-+1
-a
-#endif
-.
-/R_UnboundValue;/
-i
-#ifdef FASTR
-LibExtern SEXP FASTR_R_UnboundValue();
-#define R_UnboundValue FASTR_R_UnboundValue()
-#else
-.
-+1
-a
-#endif
-.
-/R_PreserveObject/
-i
-#ifdef FASTR
-SEXP R_PreserveObject(SEXP);
-#else
-.
-+1
-a
-#endif
-.
-/#ifdef USE_RINTERNALS/
-d
-i
-#if defined (USE_RINTERNALS_DEFS) && (defined (USE_RINTERNALS) || defined (FASTR))
-.
-/macro version of R_CheckStack/
-i
-#endif
-#ifdef USE_RINTERNALS
-
-.
-w Rinternals.h
diff --git a/com.oracle.truffle.r.native/library/grid/Makefile b/com.oracle.truffle.r.native/library/grid/Makefile
index 58f1789a96f7caa5c52cb451e834c8d46302b4de..4ef8f605d9d5e9874c1bee3581221630bb5ff06e 100644
--- a/com.oracle.truffle.r.native/library/grid/Makefile
+++ b/com.oracle.truffle.r.native/library/grid/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -21,14 +21,43 @@
 # questions.
 #
 
+.PHONY: cleanpkg
+
 OBJ = lib
 
-GNUR_C_FILES := $(notdir $(wildcard $(GNUR_HOME)/src/library/grid/src/*.c))
+GNUR_C_FILES := gpar.c just.c layout.c matrix.c register.c unit.c util.c viewport.c
+
+GNUR_GRID = $(addprefix $(GNUR_HOME)/src/library/grid/src/, grid.c)
+GRID_OBJECT = $(addprefix $(OBJ)/, grid.o)
+
+GNUR_GRID_STATE = $(addprefix $(GNUR_HOME)/src/library/grid/src/, state.c)
+GRID_STATE_OBJECT = $(addprefix $(OBJ)/, state.o)
 
-GNUR_C_OBJECTS := $(addprefix $(OBJ)/, $(GNUR_C_FILES:.c=.o))
-#$(info GNUR_C_OBJECTS=$(GNUR_C_OBJECTS))
+GNUR_C_OBJECTS := $(addprefix $(OBJ)/, $(GNUR_C_FILES:.c=.o)) $(GRID_OBJECT) $(GRID_STATE_OBJECT)
+LIB_PKG_PRE = $(GRID_OBJECT) $(GRID_STATE_OBJECT)
+CLEAN_PKG := cleanpkg
+
+# This is necessary so that #include "grid.h" works
+PKG_INCLUDES = -I $(GNUR_SRC) 
 
 include ../lib.mk
 
+# Why is this necessary? Because if grid.c and state.c have been created by editing, 
+# lib.mk will include them in C_OBJECTS but they're already in GNUR_C_OBJECTS (uncreated case)
+C_OBJECTS := $(filter-out $(GRID_OBJECT) $(GRID_STATE_OBJECT), $(C_OBJECTS))
+
+$(C_OBJECTS): | $(OBJ)
+
+$(SRC)/grid.c: $(GNUR_GRID) src/sed_grid
+	sed -f src/sed_grid $(GNUR_GRID) > src/grid.c
+
+$(SRC)/state.c: $(GNUR_GRID_STATE) src/sed_state
+	sed -f src/sed_state $(GNUR_GRID_STATE) > src/state.c
+
+# obj files from c.o.t.r.n/library/grid/src are handled in lib.mk
+# obj files from gnur to c.o.t.r.n/library/grid/lib are handled here
 $(OBJ)/%.o: $(GNUR_SRC)/%.c
-	$(CC) $(CFLAGS) $(INCLUDES)  $(SUPPRESS_WARNINGS) -c $< -o $@
+	$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+
+cleanpkg:
+	rm -f $(SRC)/grid.c $(SRC)/state.c
diff --git a/com.oracle.truffle.r.native/library/grid/src/sed_grid b/com.oracle.truffle.r.native/library/grid/src/sed_grid
new file mode 100644
index 0000000000000000000000000000000000000000..507382a2dc63e0c28ab91e959f68b16f607f88b4
--- /dev/null
+++ b/com.oracle.truffle.r.native/library/grid/src/sed_grid
@@ -0,0 +1,10 @@
+# L_initGrid gets environment from its caller, which is .External, and saves it 
+# into a static variable R_gridEvalEnv without calling R_PreserveObject. In the 
+# Gnu R world, the environment actually cannot be garbage collected, because it 
+# is grid's environment and there are references to it.
+# 
+# Moreover, grid also uses this environment to "preserve" other objects just by 
+# adding them to that environment. See ed_state where we fix code doing this to 
+# also call R_PreserveObject and R_ReleaseObject.
+# 
+s/R_gridEvalEnv = \([[:alnum:]]*\);/R_gridEvalEnv = R_PreserveObject(\1);/g
diff --git a/com.oracle.truffle.r.native/library/grid/src/sed_state b/com.oracle.truffle.r.native/library/grid/src/sed_state
new file mode 100644
index 0000000000000000000000000000000000000000..4cd242c4b41eee792e6acbe98ad2cb42ca1d471e
--- /dev/null
+++ b/com.oracle.truffle.r.native/library/grid/src/sed_state
@@ -0,0 +1,18 @@
+# see ed_grid for description of what is going on here.
+# 
+# Note: the state cannot be 'preserved' in globaliseState(SEXP) 
+# function, which would seem as appropriate place, because the 
+# state is stored into a global variable before globaliseState
+# is invoked.
+#
+# prepend R_PreserveObject call to any sd->systemSpecific assignment 
+# in form of sd->systemSpecific = (void*) variablename;
+s/sd->systemSpecific[[:space:]]*=[[:space:]]*(void\*)[[:space:]]*\([[:alnum:]_]*\);/\1 = R_PreserveObject(\1); sd->systemSpecific = (void*)\1;/g
+#
+# rename deglobaliseState to deglobaliseStateOriginal and prepend a 
+# new definition of deglobaliseState that calls R_ReleaseObject and 
+# the original function (note we need deglobaliseStateOriginal 
+# forward declaration)
+s/static void deglobaliseState(SEXP state)/static void deglobaliseStateOriginal(SEXP state);\
+static void deglobaliseState(SEXP state) { deglobaliseStateOriginal(state); R_ReleaseObject(state); }\
+static void deglobaliseStateOriginal(SEXP state)/g
diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source
new file mode 100644
index 0000000000000000000000000000000000000000..78c24caea0d6432c6894a971ae42532768cc80d4
--- /dev/null
+++ b/com.oracle.truffle.r.native/version.source
@@ -0,0 +1 @@
+2/10/17
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 0198eb0e04f8e0a9b54d20beb668b6a3f7bde66a..40b36e8afd01bb2d92e74b6bda6dbeb65c326d36 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
@@ -26,7 +26,6 @@ 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;
@@ -48,8 +47,8 @@ public abstract class APerm extends RBuiltinNode {
     private final BranchProfile emptyPermVector = BranchProfile.create();
     private final ConditionProfile mustResize = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(APerm.class);
         casts.arg("a").mustNotBeNull(RError.Message.FIRST_ARG_MUST_BE_ARRAY);
         casts.arg("perm").allowNull().mustBe(numericValue().or(stringValue()).or(complexValue())).mapIf(numericValue().or(complexValue()), asIntegerVector());
         casts.arg("resize").mustBe(numericValue().or(logicalValue()), Message.INVALID_LOGICAL, "resize").asLogicalVector().findFirst();
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 33c348630cebdb9a158e215880926a1f16ac676d..acf3a5b1ccef9d7419ebddf41ed5ae6539117822 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
@@ -18,7 +18,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RDataFactory;
@@ -30,8 +29,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class Abbrev extends RBuiltinNode {
     private final NACheck naCheck = NACheck.create();
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Abbrev.class);
         casts.arg("x").mustBe(stringValue());
         casts.arg("minlength").asIntegerVector().findFirst().notNA();
         casts.arg("use.classes").asLogicalVector().findFirst().notNA().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java
index 6f117ef49d84ed3c124eeef424b548f20537a0b1..b3604b3037b1952cbf6d1786c60895f4578107cd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/All.java
@@ -33,6 +33,10 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "all", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
 public abstract class All extends Quantifier {
 
+    static {
+        createCasts(All.class);
+    }
+
     @Override
     protected boolean emptyVectorResult() {
         return true;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java
index 053928da25d4bfc8bdf9cd7855288bc9f79efe1e..ce62baed1abe2db4b930fa56602958929a9556ab 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ 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.RASTUtils;
-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;
@@ -52,8 +51,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor;
 @RBuiltin(name = "all.names", kind = INTERNAL, parameterNames = {"expr", "functions", "max.names", "unique"}, behavior = PURE)
 public abstract class AllNames extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AllNames.class);
         casts.arg("functions").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).notNA(RRuntime.LOGICAL_FALSE);
         casts.arg("max.names").asIntegerVector().findFirst(0).notNA(0);
         casts.arg("unique").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).notNA(RRuntime.LOGICAL_TRUE);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java
index 7cf2116f10e4ea11bd8f28a7e47d51d0e6d35bb4..30375f72c6613f1bc93bfe6845189ba73c7aec68 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Any.java
@@ -33,6 +33,10 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "any", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
 public abstract class Any extends Quantifier {
 
+    static {
+        createCasts(Any.class);
+    }
+
     @Override
     protected boolean emptyVectorResult() {
         return false;
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 57c48da529aacc0ff7572c242cf1506658bf41fb..dc146c10aaf54a033654d50bf5e9e8102579ed36 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@ 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.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -56,8 +55,8 @@ public abstract class AnyNA extends RBuiltinNode {
 
     public abstract byte execute(VirtualFrame frame, Object value, boolean recursive);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AnyNA.class);
         casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java
index 0dca5bbfb11818485db259a0242c9a93e83dfe94..130ec5a77e8d0e2344b0ff675af560e2908df99f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Arg.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ 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.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
@@ -42,8 +41,8 @@ public abstract class Arg extends UnaryArithmeticBuiltinNode {
         super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Arg.class);
         casts.arg("z").mustBe(numericValue().or(complexValue()), RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java
index c239b07b293abaec17216c177dff74b1cb2e986b..3ea1d01a8f12b4d3a02e4b7a63d878b9f658d953 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,10 @@ public abstract class Args extends RBuiltinNode {
     @Child private GetFunctions.Get getNode;
     @Child private FrameFunctions.ParentFrame parentFrameNode;
 
+    static {
+        Casts.noCasts(Args.class);
+    }
+
     @Specialization
     protected Object args(VirtualFrame frame, RAbstractStringVector funName) {
         if (funName.getLength() == 0) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
index e7c0418956a2cb9348bdf83bd01a9f42e5b1cb3d..0e7f1daddea24b9076390b40a68317ed7e35f4dd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,14 +25,12 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.Function;
-
 import com.oracle.truffle.api.CompilerDirectives;
 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.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -46,7 +44,6 @@ import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -79,14 +76,9 @@ public abstract class Array extends RBuiltinNode {
         updateDimNames.executeRAbstractContainer(container, o);
     }
 
-    private String argType(Object arg) {
-        return ((RTypedValue) arg).getRType().getName();
-    }
-
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        Function<Object, Object> argType = this::argType;
-        casts.arg("data").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR_BUT_WAS, "data", argType).mustNotBeNull().mustBe(abstractVectorValue());
+    static {
+        Casts casts = new Casts(Array.class);
+        casts.arg("data").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_VECTOR_BUT_WAS, "data", typeName()).mustBe(abstractVectorValue());
         casts.arg("dim").defaultError(RError.SHOW_CALLER, RError.Message.CANNOT_BE_LENGTH, "dims", 0).mustNotBeNull().asIntegerVector().mustBe(notEmpty());
         casts.arg("dimnames").defaultError(RError.SHOW_CALLER, RError.Message.DIMNAMES_LIST).allowNull().mustBe(instanceOf(RList.class));
     }
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 cb65b88f22320b3eb45e95941ebca3477833382b..afc469496d2fef4b66feb7ab30da478b5faefde6 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,10 @@ public abstract class AsCall extends RBuiltinNode {
     private final ConditionProfile nullNamesProfile = ConditionProfile.createBinaryProfile();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
+    static {
+        Casts.noCasts(AsCall.class);
+    }
+
     @Specialization
     protected RLanguage asCallFunction(RList x) {
         // TODO error checks
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
index 04ca61957f575f005bc3c24ecad9ee162543fbae..0c000916060ff4187bd10ca3e9214b106621644f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -46,9 +45,9 @@ public abstract class AsCharacter extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().mapIf(instanceOf(RAbstractListVector.class).not(), asStringVector());
+    static {
+        Casts casts = new Casts(AsCharacter.class);
+        casts.arg("x").mapIf(instanceOf(RAbstractListVector.class).not(), asStringVector());
     }
 
     @Specialization
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 170e9ec76ac5b8ecb0b5a3575b296d6a5f15e830..a3878fe3db264360b99a8e48baa21b95de4953c4 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
@@ -49,6 +49,10 @@ public abstract class AsCharacterFactor extends RBuiltinNode {
     @Child CastToVectorNode castToVectorNode = CastToVectorNode.create();
     @Child private GetFixedAttributeNode getLevelsAttrNode = GetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
 
+    static {
+        Casts.noCasts(AsCharacterFactor.class);
+    }
+
     @Specialization
     protected RStringVector doAsCharacterFactor(Object x) {
         byte isFactor = (byte) inheritsNode.execute(x, CLASS_FACTOR_VEC, false);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java
index 814a0ec2350ab367521531643647bade7e4a1565..468752482966f3f41627408ee460d278d019bf50 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsComplex.java
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RDispatch;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -40,9 +39,9 @@ public abstract class AsComplex extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asComplexVector();
+    static {
+        Casts casts = new Casts(AsComplex.class);
+        casts.arg("x").asComplexVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
index 7f8d5c1015ee42e9828dca78e5eb8f24b4e877e8..7c65477dadaea01b5be7c7d03bf7f92fbad9f12d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-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.RDataFactory;
@@ -39,9 +38,9 @@ public abstract class AsDouble extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asDoubleVector();
+    static {
+        Casts casts = new Casts(AsDouble.class);
+        casts.arg("x").asDoubleVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
index d36f0d5089b3d68b0359f70cba925bdb3d72441b..a049ddd75dc54c4781821ef715b66ad4fc06e004 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.nodes.access.AccessArgumentNode;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
@@ -65,8 +64,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 @RBuiltin(name = "as.function.default", kind = INTERNAL, parameterNames = {"x", "envir"}, behavior = PURE)
 public abstract class AsFunction extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsFunction.class);
         casts.arg("x").mustBe(instanceOf(RAbstractListVector.class).or(instanceOf(RExpression.class)), RError.SHOW_CALLER2, RError.Message.TYPE_EXPECTED, RType.List.getName());
         casts.arg("envir").mustBe(instanceOf(REnvironment.class), RError.Message.INVALID_ENVIRONMENT);
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
index 9bc2ad81ddf43cbbfe2b04094e1653a25240a0ea..f7beffc392de4f77b2af3ee0d97f6649594bf5af 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-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.RDataFactory;
@@ -39,9 +38,9 @@ public abstract class AsInteger extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asIntegerVector();
+    static {
+        Casts casts = new Casts(AsInteger.class);
+        casts.arg("x").asIntegerVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
index fbdc14690c61b46e14d132bc7a489abfbd9c28a9..5df1046a5c2b07131232094753f0ae1ba5b7792b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-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.RDataFactory;
@@ -39,9 +38,9 @@ public abstract class AsLogical extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asLogicalVector();
+    static {
+        Casts casts = new Casts(AsLogical.class);
+        casts.arg("x").asLogicalVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java
index dafd3a6f8a5ecd8de9ec560f43221edabc0d4b49..cd935a7b146abb247afba1ce5a7ac40d0e740923 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsRaw.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-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.RDataFactory;
@@ -39,8 +38,8 @@ public abstract class AsRaw extends RBuiltinNode {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsRaw.class);
         casts.arg("x").allowNull().asRawVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
index 3add337eeddb6b8c2ec068284a7ee9ed4014c114..facf4b7d25493acf40217c6a9cf88bf2e047068a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
@@ -37,7 +37,6 @@ 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.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen.CastPairListNodeGen;
@@ -83,8 +82,8 @@ public abstract class AsVector extends RBuiltinNode {
 
     private final ConditionProfile hasClassProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AsVector.class);
         casts.arg("mode").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
index 658e91d839ae71f6f2fee68f0009df72913f1ff8..9b191ab4b93b25fb0aafd0c06591117604ba9b67 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.LoopNode;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -91,8 +90,8 @@ public abstract class Assign extends RBuiltinNode {
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Assign.class);
         casts.arg("x").asStringVector().shouldBe(singleElement(), RError.Message.ONLY_FIRST_VARIABLE_NAME).findFirst(RError.Message.INVALID_FIRST_ARGUMENT);
 
         casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(REnvironment.class, RError.Message.INVALID_ARGUMENT, "envir");
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java
index b9103fc9e473631071871f388771dbeda2e494e9..f1ef8beb37181a987574a97dd3a33f1608e1349f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AttachFunctions.java
@@ -31,7 +31,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -49,8 +48,8 @@ public class AttachFunctions {
     @RBuiltin(name = "attach", visibility = OFF, kind = INTERNAL, parameterNames = {"what", "pos", "name"}, behavior = COMPLEX)
     public abstract static class Attach extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Attach.class);
             casts.arg("what").allowNull().mustBe(instanceOf(REnvironment.class).or(instanceOf(RAbstractListVector.class)), RError.Message.ATTACH_BAD_TYPE);
             casts.arg("pos").mustBe(numericValue(), Message.MUST_BE_INTEGER, "pos").asIntegerVector();
             casts.arg("name").mustBe(stringValue());
@@ -106,8 +105,8 @@ public class AttachFunctions {
     @RBuiltin(name = "detach", visibility = OFF, kind = INTERNAL, parameterNames = {"pos"}, behavior = COMPLEX)
     public abstract static class Detach extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Detach.class);
             casts.arg("pos").mustBe(numericValue(), Message.MUST_BE_INTEGER, "pos").asIntegerVector();
         }
 
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 0329bf95e8ab9c10a0f8684e6eadb19e24095382..530f77eb8e85431d5f057eaf5ae85b75bcdbdd36 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.UpdateAttr.InternStringNode;
 import com.oracle.truffle.r.nodes.builtin.base.UpdateAttrNodeGen.InternStringNodeGen;
@@ -74,8 +73,8 @@ public abstract class Attr extends RBuiltinNode {
         return new Object[]{RMissing.instance, RMissing.instance, RRuntime.asLogical(false)};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Attr.class);
         // Note: checking RAttributable.class does not work for scalars
         // casts.arg("x").mustBe(RAttributable.class, Message.UNIMPLEMENTED_ARGUMENT_TYPE);
         casts.arg("which").mustBe(stringValue(), Message.MUST_BE_CHARACTER, "which").asStringVector().mustBe(singleElement(), RError.Message.EXACTLY_ONE_WHICH).findFirst();
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 31586b70dfd4794b64d3ff8f98dfcba869811b6f..3c751dc9906fae8a7383ce2d6b64fc22af414917 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
@@ -56,6 +56,10 @@ public abstract class Attributes extends RBuiltinNode {
     @Child private ArrayAttributeNode arrayAttrAccess = ArrayAttributeNode.create();
     @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create();
 
+    static {
+        Casts.noCasts(Attributes.class);
+    }
+
     @Specialization
     protected Object attributesNull(RAbstractContainer container,
                     @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile) {
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 576d36eda1da32515b1562e92e8ab3cef8bb72f1..005d49ee57fc65f2b4570d33060f89c9bb0bca5f 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
@@ -28,10 +28,8 @@ import static com.oracle.truffle.r.runtime.nmath.RMath.fmax2;
 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.NodeChild;
-import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.BaseGammaFunctionsFactory.DpsiFnCalcNodeGen;
 import com.oracle.truffle.r.runtime.RError;
@@ -45,7 +43,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.nmath.GammaFunctions;
 import com.oracle.truffle.r.runtime.nmath.RMath;
-import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public class BaseGammaFunctions {
@@ -73,8 +70,8 @@ public class BaseGammaFunctions {
 
         private final NACheck naValCheck = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Lgamma.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector();
         }
 
@@ -111,13 +108,13 @@ public class BaseGammaFunctions {
         private double dpsiFnCalc(double x, int n, int kode, double ans) {
             if (dpsiFnCalc == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                dpsiFnCalc = insert(DpsiFnCalcNodeGen.create(null, null, null, null));
+                dpsiFnCalc = insert(DpsiFnCalcNodeGen.create());
             }
             return dpsiFnCalc.executeDouble(x, n, kode, ans);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DiGamma.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector();
         }
 
@@ -157,8 +154,7 @@ public class BaseGammaFunctions {
         }
     }
 
-    @NodeChildren({@NodeChild(value = "x"), @NodeChild(value = "n"), @NodeChild(value = "kode"), @NodeChild(value = "ans")})
-    protected abstract static class DpsiFnCalc extends RNode {
+    protected abstract static class DpsiFnCalc extends Node {
 
         // the following is transcribed from polygamma.c
 
@@ -180,7 +176,7 @@ public class BaseGammaFunctions {
         private double dpsiFnCalc(double x, int n, int kode, double ans) {
             if (dpsiFnCalc == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                dpsiFnCalc = insert(DpsiFnCalcNodeGen.create(null, null, null, null));
+                dpsiFnCalc = insert(DpsiFnCalcNodeGen.create());
             }
             return dpsiFnCalc.executeDouble(x, n, kode, ans);
         }
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 c5370e44e0c7d7e9b8eb047dd7dec869be3c562b..fb195606ae5a5ebe010f5098fa1dde10f4d70572 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
@@ -339,7 +339,7 @@ public class BasePackage extends RBuiltinPackage {
         add(EnvFunctions.UnlockBinding.class, EnvFunctionsFactory.UnlockBindingNodeGen::create);
         add(Eval.class, EvalNodeGen::create);
         add(RecordGraphics.class, RecordGraphics::create);
-        add(WithVisible.class, WithVisibleNodeGen::create);
+        add(WithVisible.class, WithVisibleNodeGen::create, WithVisible::createSpecial);
         add(Exists.class, ExistsNodeGen::create);
         add(Expression.class, ExpressionNodeGen::create);
         add(FastRContext.R.class, FastRContextFactory.RNodeGen::create);
@@ -571,7 +571,7 @@ public class BasePackage extends RBuiltinPackage {
         add(Repeat.class, RepeatNodeGen::create);
         add(RepeatInternal.class, RepeatInternalNodeGen::create);
         add(RepeatLength.class, RepeatLengthNodeGen::create);
-        add(Return.class, ReturnNodeGen::create);
+        add(Return.class, ReturnNodeGen::create, Return::createSpecial);
         add(Rhome.class, RhomeNodeGen::create);
         add(Rm.class, RmNodeGen::create);
         add(Round.class, RoundNodeGen::create);
@@ -687,6 +687,7 @@ public class BasePackage extends RBuiltinPackage {
         add(WhichFunctions.WhichMax.class, WhichFunctions.WhichMax::create);
         add(WhichFunctions.WhichMin.class, WhichFunctions.WhichMin::create);
         add(Xtfrm.class, XtfrmNodeGen::create);
+        add(IsSingle.class, IsSingleNodeGen::create);
 
         // query
         add(RForceQueryBuiltin.class, RForceQueryBuiltinNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java
index feb0ae5f278c8bfaea909c862ae52cafb7910c97..1c9c02253cef6f4fe4698f6ebc41ffec753b712b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bincode.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
-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;
@@ -33,8 +32,8 @@ public abstract class Bincode extends RBuiltinNode {
     private final BranchProfile errorProfile = BranchProfile.create();
     private final NACheck naCheck = NACheck.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Bincode.class);
         casts.arg("x").asDoubleVector();
 
         casts.arg("breaks").asDoubleVector();
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 dd7550312ed07f7cb873a2a063c00a9b7704cb5d..14584bfb602fe33c6aaf0ebe0e2016955e4e92c9 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
@@ -41,12 +41,13 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa
 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.CallMatcherNode;
+import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
+import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
+import com.oracle.truffle.r.nodes.function.GetBaseEnvFrameNode;
 import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode;
 import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result;
-import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
+import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
 import com.oracle.truffle.r.nodes.unary.CastComplexNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -68,11 +69,13 @@ 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.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.RTypes;
 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;
@@ -100,9 +103,7 @@ public abstract class Bind extends RBaseNode {
     @Child private CastToVectorNode castVector;
     @Child private CastLogicalNode castLogical;
     @Child private GetDimAttributeNode getDimsNode;
-
-    @Child private S3FunctionLookupNode lookup;
-    @Child private CallMatcherNode callMatcher;
+    @Child private SetDimNamesAttributeNode setDimNamesNode;
 
     private final BindType type;
 
@@ -114,17 +115,6 @@ public abstract class Bind extends RBaseNode {
     protected final ValueProfile resultProfile = ValueProfile.createClassProfile();
     protected final ValueProfile vectorProfile = ValueProfile.createClassProfile();
 
-    @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create();
-
-    protected int precedence(RArgsValuesAndNames args) {
-        int precedence = -1;
-        Object[] array = args.getArguments();
-        for (int i = 0; i < array.length; i++) {
-            precedence = Math.max(precedence, precedenceNode.executeInteger(array[i], false));
-        }
-        return precedence;
-    }
-
     protected Bind(BindType type) {
         this.type = type;
     }
@@ -154,52 +144,25 @@ public abstract class Bind extends RBaseNode {
     }
 
     @SuppressWarnings("unused")
-    @Specialization(guards = "precedence == NO_PRECEDENCE")
+    @Specialization(guards = {"precedence == NO_PRECEDENCE"})
     protected RNull allNull(VirtualFrame frame, int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, int precedence) {
         return RNull.instance;
     }
 
-    private static final ArgumentsSignature SIGNATURE = ArgumentsSignature.get("deparse.level", "...");
-
-    private static final RStringVector DATA_FRAME_CLASS = RDataFactory.createStringVectorFromScalar("data.frame");
-
-    @Specialization(guards = {"args.length > 0", "isDataFrame(args)"})
-    protected Object allDataFrame(VirtualFrame frame, int deparseLevel, @SuppressWarnings("unused") Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) {
-        if (lookup == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            lookup = insert(S3FunctionLookupNode.create(false, false));
-        }
-        Result lookupResult = lookup.execute(frame, type.toString(), DATA_FRAME_CLASS, null, frame.materialize(), null);
-        if (lookupResult == null) {
-            throw RInternalError.shouldNotReachHere();
-        }
-        if (callMatcher == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            callMatcher = insert(CallMatcherNode.create(false));
-        }
-        return callMatcher.execute(frame, SIGNATURE, new Object[]{deparseLevel, promiseArgs}, lookupResult.function, lookupResult.targetFunctionName, lookupResult.createS3Args(frame));
-    }
-
     private Object bindInternal(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast, SetDimAttributeNode setDimNode,
-                    SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getDimNamesNode, GetNamesAttributeNode getNamesNode) {
+                    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];
         boolean complete = true;
         int ind = 0;
         naCheck.enable(true);
+        RAbstractVector fromNotNullArgVector = null;
         for (int i = 0; i < args.length; i++) {
-            if (vecNames != null) {
-                nonNullNames.enter();
-                vecNames[ind] = signature.getName(i);
-                naCheck.check(vecNames[ind]);
-            }
-            Object result = castNode.execute(args[i]);
-            RAbstractVector vector;
-            if (needsVectorCast) {
-                vector = castVector(result);
-            } else {
-                vector = (RAbstractVector) result;
+            setVectorNames(vecNames, ind, signature.getName(i));
+            RAbstractVector vector = getVector(args[i], castNode, needsVectorCast);
+            if (fromNotNullArgVector == null && !RTypes.isRNull(args[i])) {
+                fromNotNullArgVector = vector;
             }
             if (emptyVectorProfile.profile(vector.getLength() == 0)) {
                 // nothing to do
@@ -209,25 +172,14 @@ public abstract class Bind extends RBaseNode {
                 ind++;
             }
         }
+        boolean allEmpty = ind == 0;
         if (emptyVectorProfile.profile(ind < args.length)) {
-            if (allEmptyVectorProfile.profile(ind == 0)) {
+            if (allEmptyVectorProfile.profile(allEmpty)) {
                 for (int i = 0; i < args.length; i++) {
-                    if (vecNames != null) {
-                        nonNullNames.enter();
-                        vecNames[i] = signature.getName(i);
-                        naCheck.check(vecNames[i]);
-                    }
-                    Object result = castNode.execute(args[i]);
-                    RAbstractVector vector;
-                    if (needsVectorCast) {
-                        vector = castVector(result);
-                    } else {
-                        vector = (RAbstractVector) result;
-                    }
-                    vectors[i] = vector;
-                    complete &= vector.isComplete();
+                    setVectorNames(vecNames, i, signature.getName(i));
+                    vectors[i] = getVector(args[i], castNode, needsVectorCast);
+                    complete &= vectors[i].isComplete();
                 }
-                ind = args.length;
             } else {
                 if (vecNames != null) {
                     nonNullNames.enter();
@@ -236,71 +188,97 @@ public abstract class Bind extends RBaseNode {
                 vectors = Arrays.copyOf(vectors, ind);
             }
         }
+
+        int[] bindDims = new int[vectors.length];
+        int[] resultDimensions = new int[2];
+        boolean rowsAndColumnsNotEqual = getResultDimensions(vectors, resultDimensions, bindDims);
+        RVector<?> resultVec;
+        if (fromNotNullArgVector != null) {
+            resultVec = resultProfile.profile(fromNotNullArgVector.createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
+        } else {
+            resultVec = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
+        }
+
         if (type == BindType.cbind) {
-            return genericCBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
+            return genericCBind(promiseArgs, vectors, resultVec, resultDimensions, bindDims, rowsAndColumnsNotEqual, allEmpty, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode,
+                            getDimNamesNode, getNamesNode);
+        } else {
+            return genericRBind(promiseArgs, vectors, resultVec, resultDimensions, bindDims, rowsAndColumnsNotEqual, allEmpty, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode,
+                            getDimNamesNode, getNamesNode);
+        }
+    }
+
+    private RAbstractVector getVector(Object arg, CastNode castNode, boolean needsVectorCast) {
+        Object result = castNode.execute(arg);
+        RAbstractVector vector;
+        if (needsVectorCast) {
+            vector = castVector(result);
         } else {
-            return genericRBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode, getDimNamesNode, getNamesNode);
+            vector = (RAbstractVector) result;
         }
+        return vector;
     }
 
-    @Specialization(guards = {"precedence == LOGICAL_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
-    protected Object allLogical(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence,
+    private void setVectorNames(String[] vecNames, int vectorInd, String signatureName) {
+        if (vecNames != null) {
+            nonNullNames.enter();
+            vecNames[vectorInd] = signatureName;
+            naCheck.check(vecNames[vectorInd]);
+        }
+    }
+
+    @Specialization(guards = {"precedence == LOGICAL_PRECEDENCE", "args.length > 1"})
+    protected Object allLogical(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence,  //
                     @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);
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, 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,
+    @Specialization(guards = {"precedence == INT_PRECEDENCE", "args.length > 1"})
+    protected Object allInt(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @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);
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, 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,
+    @Specialization(guards = {"precedence == DOUBLE_PRECEDENCE", "args.length > 1"})
+    protected Object allDouble(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @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);
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, 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,
+    @Specialization(guards = {"precedence == STRING_PRECEDENCE", "args.length> 1"})
+    protected Object allString(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @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);
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, 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,
+    @Specialization(guards = {"precedence == COMPLEX_PRECEDENCE", "args.length > 1"})
+    protected Object allComplex(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @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);
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, 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,
+    @Specialization(guards = {"precedence == LIST_PRECEDENCE", "args.length > 1"})
+    protected Object allList(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @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);
+        return bindInternal(deparseLevel, args, promiseArgs, cast, false, setDimNode, getDimNamesNode, getNamesNode);
     }
 
     /**
@@ -448,49 +426,12 @@ public abstract class Bind extends RBaseNode {
         return RRuntime.NAMES_ATTR_EMPTY_VALUE;
     }
 
-    @Child private InheritsCheckNode inheritsCheck = new InheritsCheckNode(RRuntime.CLASS_DATA_FRAME);
-
-    protected boolean isDataFrame(Object[] args) {
-        for (int i = 0; i < args.length; i++) {
-            if (inheritsCheck.execute(args[i])) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    @RBuiltin(name = "cbind", kind = INTERNAL, parameterNames = {"deparse.level", "..."}, behavior = COMPLEX)
-    public abstract static class CbindInternal extends RBuiltinNode {
-
-        @Child private Bind bind = BindNodeGen.create(BindType.cbind);
-        @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create();
-
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("deparse.level").asIntegerVector().findFirst(0);
-        }
-
-        private int precedence(Object[] args) {
-            int precedence = -1;
-            for (int i = 0; i < args.length; i++) {
-                precedence = Math.max(precedence, precedenceNode.executeInteger(args[i], false));
-            }
-            return precedence;
-        }
-
-        @Specialization
-        protected Object bind(VirtualFrame frame, int deparseLevel, RArgsValuesAndNames args) {
-            return bind.execute(frame, deparseLevel, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments()));
-        }
-    }
-
     private final BranchProfile everSeenNotEqualRows = BranchProfile.create();
     private final BranchProfile everSeenNotEqualColumns = BranchProfile.create();
+    private final ConditionProfile needsDimNames = ConditionProfile.createBinaryProfile();
 
     @Specialization(guards = {"precedence != NO_PRECEDENCE", "args.length == 1"})
     protected Object allOneElem(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
                     @Cached("create()") GetNamesAttributeNode getNamesNode) {
         RAbstractVector vec = vectorProfile.profile(castVector(args[0]));
         int[] rawDimensions = getVectorDimensions(vec);
@@ -524,19 +465,15 @@ public abstract class Bind extends RBaseNode {
 
         int[] dims = getDimensions(vec, rawDimensions);
         RVector<?> res = (RVector<?>) vec.copyWithNewDimensions(dims);
-        setDimNamesNode.execute(res, RDataFactory.createList(type == BindType.cbind ? new Object[]{dimNamesA, dimNamesB} : new Object[]{dimNamesB, dimNamesA}));
-        res.copyRegAttributesFrom(vec);
+        if (needsDimNames.profile(vec.getLength() == 0 || dimNamesA != RNull.instance || dimNamesB != RNull.instance)) {
+            setDimNames(res, RDataFactory.createList(type == BindType.cbind ? new Object[]{dimNamesA, dimNamesB} : new Object[]{dimNamesB, dimNamesA}));
+        }
         return res;
     }
 
-    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);
-        RAbstractVector first = vectorProfile.profile(vectors[0]);
-        RVector<?> result = resultProfile.profile(first.createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
+    public RVector<?> genericCBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, RVector<?> result, int[] resultDimensions, int[] secondDims, boolean rowsAndColumnsNotEqual,
+                    boolean allEmpty, String[] vecNames, boolean vecNamesComplete, int deparseLevel,
+                    SetDimAttributeNode setDimNode, GetDimNamesAttributeNode getDimNamesNode, GetNamesAttributeNode getNamesNode) {
 
         int ind = 0;
         Object rowDimResultNames = RNull.instance;
@@ -564,7 +501,7 @@ public abstract class Bind extends RBaseNode {
             for (int j = 0; j < vecLength; j++) {
                 result.transferElementSameType(ind++, vec, j);
             }
-            if (notEqualRows) {
+            if (rowsAndColumnsNotEqual) {
                 everSeenNotEqualRows.enter();
                 if (vecLength < resultDimensions[0]) {
                     // re-use vector elements
@@ -581,42 +518,116 @@ public abstract class Bind extends RBaseNode {
         }
         Object colDimResultNames = allColDimNamesNull ? RNull.instance : RDataFactory.createStringVector(colDimNamesArray, vecNamesComplete);
         setDimNode.setDimensions(result, resultDimensions);
-        setDimNamesNode.setDimNames(result, RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
+        if (needsDimNames.profile(allEmpty || rowDimResultNames != RNull.instance || colDimResultNames != RNull.instance)) {
+            setDimNames(result, RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
+        }
         return result;
     }
 
+    @RBuiltin(name = "cbind", kind = INTERNAL, parameterNames = {"deparse.level", "..."}, behavior = COMPLEX)
+    public abstract static class CbindInternal extends AbstractBind {
+        public CbindInternal() {
+            super(BindType.cbind);
+        }
+
+        static {
+            createCasts(CbindInternal.class);
+        }
+    }
+
     @RBuiltin(name = "rbind", kind = INTERNAL, parameterNames = {"deparse.level", "..."}, behavior = COMPLEX)
-    public abstract static class RbindInternal extends RBuiltinNode {
+    public abstract static class RbindInternal extends AbstractBind {
+        public RbindInternal() {
+            super(BindType.rbind);
+        }
+
+        static {
+            createCasts(RbindInternal.class);
+        }
+    }
+
+    protected abstract static class AbstractBind extends RBuiltinNode {
+        @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(false, false);
+        private final ConditionProfile hasClassProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile hasDispatchFunction = ConditionProfile.createBinaryProfile();
+
+        @Child private Bind bind;
+        @Child private RExplicitCallNode dispatchCallNode;
+        @Child private PrecedenceNode precedenceNode;
 
-        @Child private Bind bind = BindNodeGen.create(BindType.rbind);
-        @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create();
+        @Child private S3FunctionLookupNode lookup;
+        @Child private GetBaseEnvFrameNode getBaseEnv;
+
+        private final BindType type;
+
+        public AbstractBind(BindType type) {
+            this.type = type;
+        }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        protected static Casts createCasts(Class<? extends AbstractBind> extCls) {
+            Casts casts = new Casts(extCls);
             casts.arg("deparse.level").asIntegerVector().findFirst(0);
+            return casts;
         }
 
-        private int precedence(Object[] args) {
+        @Specialization
+        protected Object bind(VirtualFrame frame, int deparseLevel, RArgsValuesAndNames args) {
+            RFunction dispatchFunction = createDispatchFunction(frame, args.getArguments());
+            if (hasDispatchFunction.profile(dispatchFunction != null)) {
+                if (dispatchCallNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    dispatchCallNode = insert(RExplicitCallNode.create());
+                }
+                return dispatchCallNode.execute(frame, dispatchFunction, (RArgsValuesAndNames) RArguments.getArgument(frame, 0));
+            } else {
+                if (bind == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    bind = insert(BindNodeGen.create(type));
+                }
+                return bind.execute(frame, deparseLevel, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments()));
+            }
+        }
+
+        protected int precedence(Object[] args) {
             int precedence = -1;
+            if (precedenceNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                precedenceNode = insert(PrecedenceNodeGen.create());
+            }
             for (int i = 0; i < args.length; i++) {
                 precedence = Math.max(precedence, precedenceNode.executeInteger(args[i], false));
             }
             return precedence;
         }
 
-        @Specialization
-        protected Object bind(VirtualFrame frame, int deparseLevel, RArgsValuesAndNames args) {
-            return bind.execute(frame, deparseLevel, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments()));
+        private RFunction createDispatchFunction(VirtualFrame frame, Object[] args) {
+            Result result = null;
+            for (Object arg : args) {
+                RStringVector clazz = classHierarchy.execute(arg);
+                if (hasClassProfile.profile(clazz != null)) {
+                    if (lookup == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        lookup = insert(S3FunctionLookupNode.create(false, false));
+                        getBaseEnv = insert(GetBaseEnvFrameNode.create());
+                    }
+                    Result r = lookup.execute(frame, type.toString(), clazz, null, frame.materialize(), getBaseEnv.execute());
+                    if (r != null) {
+                        if (result == null) {
+                            result = r;
+                        } else if (!result.targetFunctionName.equals(r.targetFunctionName)) {
+                            return null;
+                        }
+                    }
+                }
+            }
+            return result != null ? result.function : null;
         }
-    }
 
-    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];
-        boolean notEqualColumns = getResultDimensions(vectors, resultDimensions, firstDims);
-        RVector<?> result = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
+    public RVector<?> genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, RVector<?> result, int[] resultDimensions, int[] firstDims, boolean rowsAndColumnsNotEqual,
+                    boolean allEmpty, String[] vecNames, boolean vecNamesComplete, int deparseLevel,
+                    SetDimAttributeNode setDimNode, GetDimNamesAttributeNode getDimNamesNode, GetNamesAttributeNode getNamesNode) {
 
         Object colDimResultNames = RNull.instance;
         String[] rowDimNamesArray = new String[resultDimensions[0]];
@@ -648,7 +659,7 @@ public abstract class Bind extends RBaseNode {
                     result.transferElementSameType(j * resultDimensions[0] + k, vec, srcInd++);
                 }
             }
-            if (notEqualColumns) {
+            if (rowsAndColumnsNotEqual) {
                 everSeenNotEqualColumns.enter();
                 if (j < resultDimensions[1]) {
                     // re-use vector elements
@@ -667,7 +678,17 @@ public abstract class Bind extends RBaseNode {
         }
         Object rowDimResultNames = allRowDimNamesNull ? RNull.instance : RDataFactory.createStringVector(rowDimNamesArray, vecNamesComplete);
         setDimNode.setDimensions(result, resultDimensions);
-        setDimNamesNode.setDimNames(result, RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
+        if (needsDimNames.profile(allEmpty || rowDimResultNames != RNull.instance || colDimResultNames != RNull.instance)) {
+            setDimNames(result, RDataFactory.createList(new Object[]{rowDimResultNames, colDimResultNames}));
+        }
         return result;
     }
+
+    private void setDimNames(RVector<?> result, RList dimNames) {
+        if (setDimNamesNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            setDimNamesNode = insert(SetDimNamesAttributeNode.create());
+        }
+        setDimNamesNode.setDimNames(result, dimNames);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java
index ae96659c840be4306e46f65b4fa4b2e01beabf9e..9fe775ec76542ac41c9933fc3e37c2bc649c464e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BitwiseFunctions.java
@@ -19,15 +19,13 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.shouldBe;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.Function;
-
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
@@ -137,19 +135,15 @@ public class BitwiseFunctions {
             }
             return RDataFactory.createIntVector(na, RDataFactory.INCOMPLETE_VECTOR);
         }
-
-        protected Function<Object, String> getArgType() {
-            return x -> typeofA.execute(x).getName();
-        }
     }
 
     @RBuiltin(name = "bitwiseAnd", kind = INTERNAL, parameterNames = {"a", "b"}, behavior = PURE)
     public abstract static class BitwiseAnd extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
-            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+        static {
+            Casts casts = new Casts(BitwiseAnd.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.AND.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -167,10 +161,10 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseOr", kind = INTERNAL, parameterNames = {"a", "b"}, behavior = PURE)
     public abstract static class BitwiseOr extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
-            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+        static {
+            Casts casts = new Casts(BitwiseOr.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.OR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -188,10 +182,10 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseXor", kind = INTERNAL, parameterNames = {"a", "b"}, behavior = PURE)
     public abstract static class BitwiseXor extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
-            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+        static {
+            Casts casts = new Casts(BitwiseXor.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+            casts.arg("b").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.XOR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
         }
 
         @Specialization
@@ -209,9 +203,9 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseShiftR", kind = INTERNAL, parameterNames = {"a", "n"}, behavior = PURE)
     public abstract static class BitwiseShiftR extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+        static {
+            Casts casts = new Casts(BitwiseShiftR.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.SHIFTR.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
             casts.arg("n").mapIf(stringValue(), asStringVector(), asIntegerVector());
         }
 
@@ -236,9 +230,9 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseShiftL", kind = INTERNAL, parameterNames = {"a", "n"}, behavior = PURE)
     public abstract static class BitwiseShiftL extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.ROOTNODE, RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.SHIFTL.name).mustBe(
+        static {
+            Casts casts = new Casts(BitwiseShiftL.class);
+            casts.arg("a").defaultError(RError.ROOTNODE, RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.SHIFTL.name).mustBe(
                             doubleValue().or(integerValue())).asIntegerVector();
             casts.arg("n").allowNull().mapIf(stringValue(), chain(asStringVector()).with(shouldBe(anyValue().not(), RError.SHOW_CALLER, RError.Message.NA_INTRODUCED_COERCION)).end(),
                             asIntegerVector());
@@ -265,10 +259,12 @@ public class BitwiseFunctions {
     @RBuiltin(name = "bitwiseNot", kind = INTERNAL, parameterNames = {"a"}, behavior = PURE)
     public abstract static class BitwiseNot extends BasicBitwise {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, getArgType(), Operation.NOT.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
-        }
+        // @formatter:off
+    static {
+        Casts casts = new Casts(BitwiseNot.class);
+            casts.arg("a").defaultError(RError.Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, typeName(), Operation.NOT.name).mustBe(doubleValue().or(integerValue())).asIntegerVector();
+    }
+        //@formatter:on
 
         @Specialization
         protected Object bitwNot(RAbstractIntVector a) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java
index e852f86379df5b2dbd48b70d9c83c6c3dad45227..53812789a2944309cbbdf2ef82272156fee822a9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Body.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "body", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
 public abstract class Body extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Body.class);
+    }
+
     @Specialization
     protected Object doBody(RFunction fun) {
         FunctionDefinitionNode fdn = (FunctionDefinitionNode) fun.getRootNode();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
index 207e01ce5d4a49d0fd63ce567e2f5e3e000d2ee4..2e2226c33973bc0588b6fa9d509179b91bcd9fa8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
@@ -22,7 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.anyValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gt;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
@@ -34,7 +34,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.helpers.BrowserInteractNode;
 import com.oracle.truffle.r.nodes.builtin.helpers.BrowserInteractNodeGen;
@@ -61,10 +60,10 @@ public class BrowserFunctions {
             return new Object[]{"", RNull.instance, RRuntime.LOGICAL_TRUE, 0};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(BrowserNode.class);
             // TODO: add support for conditions conditions
-            casts.arg("condition").allowNull().mustBe(anyValue().not(), RError.Message.GENERIC, "Only NULL conditions currently supported in browser");
+            casts.arg("condition").mustBe(nullValue(), RError.Message.GENERIC, "Only NULL conditions currently supported in browser");
             casts.arg("expr").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
             casts.arg("skipCalls").asIntegerVector().findFirst(0);
         }
@@ -102,8 +101,8 @@ public class BrowserFunctions {
 
     private abstract static class RetrieveAdapter extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RetrieveAdapter.class);
             casts.arg("n").asIntegerVector().findFirst(0).mustBe(gt(0), Message.POSITIVE_CONTEXTS);
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
index b816d94c6815e3ca554e6af42747a79e2a6b0820..8680eccad330fbf154b34fd6b2760027bd4c48d5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.library.utils.Crc64;
-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;
@@ -39,9 +38,9 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "crc64", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class CRC64 extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").defaultError(RError.NO_CALLER, Message.INPUT_MUST_BE_STRING).mustNotBeNull().mustBe(stringValue());
+    static {
+        Casts casts = new Casts(CRC64.class);
+        casts.arg("x").defaultError(RError.NO_CALLER, Message.INPUT_MUST_BE_STRING).mustBe(stringValue());
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java
index 9c0d5bd0f09e1fcc36073b2b43ea76ef84a00536..d95ff7128f3770fff7879ddaf065c0641d266c2f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CacheClass.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -18,7 +18,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -28,8 +27,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = ".cache_class", kind = PRIMITIVE, parameterNames = {"class", "extends"}, behavior = COMPLEX)
 public abstract class CacheClass extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CacheClass.class);
         casts.arg("class").defaultError(RError.Message.GENERIC, "invalid class argument to internal .class_cache").mustBe(stringValue()).asStringVector().findFirst();
         // apparently, "extends" does not have to be a string vector (GNU R will not signal this
         // error) - but it does not seem to make much sense and it's doubtful if it's worth
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java
index b219b18a59b1eae4700ad3e57955c31ca3ae14ab..ed84a24405e3deb35548b798fb1de41f4fb6f895 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-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.RError;
@@ -64,8 +63,8 @@ public abstract class Call extends RBuiltinNode {
         return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Call.class);
         casts.arg("").mustBe(stringValue(), RError.Message.FIRST_ARG_MUST_BE_STRING).asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
index f42bc2c3c55879ee53857a239cde26a8a31d9605..d1e14444e7d9e2e0985a955a947e8b3622d5c25b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,6 @@ import java.util.ArrayList;
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.ToStringNode;
 import com.oracle.truffle.r.nodes.unary.ToStringNodeGen;
@@ -77,8 +76,8 @@ public abstract class Cat extends RBuiltinNode {
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Cat.class);
         casts.arg("sep").mustBe(stringValue(), RError.Message.INVALID_SEP);
 
         casts.arg("file").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java
index b8cf2bdb964b9148910210cbebf9a314c7be6118..97a39652446ab3a30f9a514bf3c94bbe1ee7fb0e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ceiling.java
@@ -29,7 +29,6 @@ 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.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
@@ -47,16 +46,10 @@ public abstract class Ceiling extends UnaryArithmeticBuiltinNode {
         super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).
-            mustBe(numericValue()).
-            asDoubleVector(true, true, true);
-        //@formatter:on
+    static {
+        Casts casts = new Casts(Ceiling.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustNotBeNull().mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector(true,
+                        true, true);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java
index 335418deeb7d23845198344b06c82f5850e81256..86c6b72e20b2213e78770ee652c63338a694da7f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CharMatch.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -15,7 +15,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -28,8 +27,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "charmatch", kind = INTERNAL, parameterNames = {"x", "table", "noMatch"}, behavior = PURE)
 public abstract class CharMatch extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CharMatch.class);
         casts.arg("x").mustBe(stringValue(), RError.NO_CALLER, Message.ARG_IS_NOT_OF_MODE, "character");
         casts.arg("table").mustBe(stringValue(), RError.NO_CALLER, Message.ARG_IS_NOT_OF_MODE, "character");
         casts.arg("noMatch").asIntegerVector().findFirst(RRuntime.INT_NA);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java
index 7a63eaf5b95e3e15a260d7335ef085a125788fd2..c72287f73e7e01b29521610aaaefac601bf29f24 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ChooseBuiltin.java
@@ -32,7 +32,6 @@ import java.util.function.IntToDoubleFunction;
 import java.util.function.IntUnaryOperator;
 
 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.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -53,8 +52,8 @@ public abstract class ChooseBuiltin extends RBuiltinNode {
 
     private final NACheck na = NACheck.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ChooseBuiltin.class);
         casts.arg("n").mustBe(numericValue(), RError.SHOW_CALLER, Message.NON_NUMERIC_MATH).mapIf(logicalValue(), asIntegerVector());
         casts.arg("k").mustBe(numericValue(), RError.SHOW_CALLER, Message.NON_NUMERIC_MATH).mapIf(logicalValue(), asIntegerVector());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java
index 99cca9a9198ce462fbd6bec2319020513232b39e..242bce76a30f0d1b7d53f5ce97e6ae316a2e6b92 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Col.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import java.util.Arrays;
 
 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.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -41,8 +40,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "col", kind = INTERNAL, parameterNames = {"dims"}, behavior = PURE)
 public abstract class Col extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Col.class);
         casts.arg("dims").defaultError(RError.SHOW_CALLER, RError.Message.MATRIX_LIKE_REQUIRED, "col").mustBe(integerValue()).asIntegerVector().mustBe(size(2));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java
index 744d723842fcdc2439c30c33c08afc7157a10136..2b6583e04b69cb064a65fa9d85203447db6744c2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColMeans.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -29,6 +29,10 @@ public abstract class ColMeans extends ColSumsBase {
 
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
 
+    static {
+        createCasts(ColMeans.class);
+    }
+
     @Specialization(guards = "!naRm")
     protected RDoubleVector colMeansNaRmFalse(RAbstractDoubleVector x, int rowNum, int colNum, @SuppressWarnings("unused") boolean naRm) {
         checkVectorLength(x, rowNum, colNum);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java
index bafef83f8fa17d1eb8064ef03f46f05de8534d92..a713374055b253babc1f0261dbe4974dc2f5a53c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSums.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,10 @@ public abstract class ColSums extends ColSumsBase {
     private final ConditionProfile removeNA = ConditionProfile.createBinaryProfile();
     private final ValueProfile concreteVectorProfile = ValueProfile.createClassProfile();
 
+    static {
+        createCasts(ColSums.class);
+    }
+
     @Specialization
     protected RDoubleVector colSums(RAbstractDoubleVector x, int rowNum, int colNum, boolean rnaParam) {
         checkVectorLength(x, rowNum, colNum);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java
index 86d65c04da3c9a1f480b306ad8d39fe34c141687..34215dc57fa37720827f7cbce88ffce610f7ee76 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ColSumsBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.RError.Message.INVALID_ARGUMENT;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-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;
@@ -47,12 +46,13 @@ public abstract class ColSumsBase extends RBuiltinNode {
     protected final NACheck na = NACheck.create();
     private final ConditionProfile vectorLengthProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected final void createCasts(CastBuilder casts) {
+    protected static Casts createCasts(Class<? extends ColSumsBase> extCls) {
+        Casts casts = new Casts(extCls);
         casts.arg("X").mustBe(numericValue(), RError.SHOW_CALLER, RError.Message.X_NUMERIC);
         casts.arg("m").defaultError(RError.SHOW_CALLER, INVALID_ARGUMENT, "n").asIntegerVector().findFirst().notNA(RError.NO_CALLER, RError.Message.VECTOR_SIZE_NA);
         casts.arg("n").defaultError(RError.SHOW_CALLER, INVALID_ARGUMENT, "p").asIntegerVector().findFirst().notNA(RError.NO_CALLER, RError.Message.VECTOR_SIZE_NA);
         casts.arg("na.rm").asLogicalVector().findFirst().notNA().map(toBoolean());
+        return casts;
     }
 
     protected final void checkVectorLength(RAbstractVector x, int rowNum, int colNum) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java
index 0be1946f7546c82aa894ae2d98332260a1c1d311..9fa28b86e33fd778f08c9a0d7512b16ddec949b9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Colon.java
@@ -58,6 +58,10 @@ public abstract class Colon extends RBuiltinNode {
     @Child private ColonCastNode rightCast = ColonCastNodeGen.create();
     @Child private ColonInternal internal = ColonInternalNodeGen.create();
 
+    static {
+        Casts.noCasts(Colon.class);
+    }
+
     @Specialization
     protected RSequence colon(Object left, Object right) {
         return internal.execute(leftCast.execute(left), rightCast.execute(right));
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 91d39ec70e14bc02089f8b717c0820bbc0486d76..1e068b47c7802987bc7b3c80b8362fc3a6d8819c 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
@@ -49,7 +49,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 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;
 import com.oracle.truffle.r.nodes.unary.CastComplexNodeGen;
@@ -104,8 +103,8 @@ public abstract class Combine extends RBuiltinNode {
     private final ConditionProfile hasNewNamesProfile = ConditionProfile.createBinaryProfile();
     @CompilationFinal private final ValueProfile[] argProfiles = new ValueProfile[MAX_PROFILES];
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Combine.class);
         casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
     }
 
@@ -120,7 +119,7 @@ public abstract class Combine extends RBuiltinNode {
         return args.getArgument(0);
     }
 
-    @Specialization(contains = "combineSimple", limit = "1", guards = {"!recursive", "args.getSignature() == cachedSignature", "cachedPrecedence == precedence(args, cachedSignature.getLength())"})
+    @Specialization(replaces = "combineSimple", limit = "1", guards = {"!recursive", "args.getSignature() == cachedSignature", "cachedPrecedence == precedence(args, cachedSignature.getLength())"})
     protected Object combineCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean recursive,
                     @Cached("args.getSignature()") ArgumentsSignature cachedSignature,
                     @Cached("precedence( args, cachedSignature.getLength())") int cachedPrecedence,
@@ -155,7 +154,7 @@ public abstract class Combine extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    @Specialization(limit = "COMBINE_CACHED_LIMIT", contains = "combineCached", guards = {"!recursive", "cachedPrecedence == precedence(args)"})
+    @Specialization(limit = "COMBINE_CACHED_LIMIT", replaces = "combineCached", guards = {"!recursive", "cachedPrecedence == precedence(args)"})
     protected Object combine(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean recursive,
                     @Cached("precedence(args, args.getLength())") int cachedPrecedence,
                     @Cached("createCast(cachedPrecedence)") CastNode cast,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java
index fd951173e3a2144253f774b7499ef39acffe8451..7fb2b3ce4d4c9c558cda43fd5bff4ff849c9a436 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CompileFunctions.java
@@ -26,7 +26,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
@@ -38,8 +37,8 @@ public class CompileFunctions {
     @RBuiltin(name = "compilePKGS", kind = INTERNAL, parameterNames = "enable", behavior = PURE)
     public abstract static class CompilePKGS extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(CompilePKGS.class);
             casts.arg("enable").asIntegerVector().findFirst(0);
         }
 
@@ -51,8 +50,9 @@ public class CompileFunctions {
 
     @RBuiltin(name = "enableJIT", kind = INTERNAL, parameterNames = "level", behavior = PURE)
     public abstract static class EnableJIT extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(EnableJIT.class);
             casts.arg("level").asIntegerVector().findFirst(0);
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
index a18522b37689d92276fc10e58cf79fae4ef4fcd0..f8826494d7df98c923ecb41e5cdad4ec5a076837 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-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.RError.Message;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 @RBuiltin(name = "complex", kind = INTERNAL, parameterNames = {"length.out", "real", "imaginary"}, behavior = PURE)
 public abstract class Complex extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Complex.class);
         casts.arg("length.out").asIntegerVector().findFirst(Message.INVALID_LENGTH);
         casts.arg("real").mapNull(emptyDoubleVector()).asDoubleVector();
         casts.arg("imaginary").mapNull(emptyDoubleVector()).asDoubleVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java
index d9d86038cfa8c8d85b183a42bf9458079eb4bac6..b56352f79199d784967ff6027ba18aa6da154b96 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java
@@ -26,7 +26,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
@@ -58,8 +57,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".addCondHands", visibility = OFF, kind = INTERNAL, parameterNames = {"classes", "handlers", "parentenv", "target", "calling"}, behavior = COMPLEX)
     public abstract static class AddCondHands extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(AddCondHands.class);
             casts.arg("classes").allowNull().mustBe(stringValue()).asStringVector();
             casts.arg("handlers").allowNull().mustBe(instanceOf(RList.class));
             casts.arg("calling").asLogicalVector().findFirst();
@@ -116,15 +116,16 @@ public class ConditionFunctions {
             }
         }
 
-        protected void restart(CastBuilder casts) {
+        protected static void restart(Casts casts) {
             casts.arg("restart").mustBe(instanceOf(RList.class), RError.Message.BAD_RESTART);
         }
     }
 
     @RBuiltin(name = ".addRestart", kind = INTERNAL, parameterNames = "restart", behavior = COMPLEX)
     public abstract static class AddRestart extends RestartAdapter {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(AddRestart.class);
             restart(casts);
         }
 
@@ -150,8 +151,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".getRestart", kind = INTERNAL, parameterNames = "restart", behavior = COMPLEX)
     public abstract static class GetRestart extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(GetRestart.class);
             casts.arg("restart").asIntegerVector().findFirst();
         }
 
@@ -164,8 +166,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".invokeRestart", kind = INTERNAL, parameterNames = {"restart", "args"}, behavior = COMPLEX)
     public abstract static class InvokeRestart extends RestartAdapter {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(InvokeRestart.class);
             restart(casts);
         }
 
@@ -183,6 +186,11 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".signalCondition", kind = INTERNAL, parameterNames = {"condition", "msg", "call"}, behavior = COMPLEX)
     public abstract static class SignalCondition extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(SignalCondition.class);
+        }
+
         @Specialization
         protected RNull signalCondition(RList condition, RAbstractStringVector msg, Object call) {
             RErrorHandling.signalCondition(condition, msg.getDataAt(0), call);
@@ -200,8 +208,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = "seterrmessage", visibility = OFF, kind = INTERNAL, parameterNames = "msg", behavior = COMPLEX)
     public abstract static class Seterrmessage extends RBuiltinNode {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Seterrmessage.class);
             casts.arg("msg").defaultError(RError.Message.ERR_MSG_MUST_BE_STRING).mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
 
@@ -214,8 +223,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".dfltWarn", kind = INTERNAL, parameterNames = {"message", "call"}, behavior = COMPLEX)
     public abstract static class DfltWarn extends RBuiltinNode {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DfltWarn.class);
             casts.arg("message").defaultError(RError.Message.ERR_MSG_BAD).mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
 
@@ -228,8 +238,9 @@ public class ConditionFunctions {
 
     @RBuiltin(name = ".dfltStop", kind = INTERNAL, parameterNames = {"message", "call"}, behavior = COMPLEX)
     public abstract static class DfltStop extends RBuiltinNode {
-        @Override
-        public void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DfltStop.class);
             casts.arg("message").defaultError(RError.Message.ERR_MSG_BAD).mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
index ef10df7ffd66c8a41fd13f2d209b6586391cca38..59a02ba8003fad19929e6112d91fe9f67f10fe03 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
@@ -57,7 +57,7 @@ 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.dsl.TypeSystemReference;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.ConnectionFunctionsFactory.WriteDataNodeGen;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.HeadPhaseBuilder;
@@ -134,52 +134,52 @@ public abstract class ConnectionFunctions {
         }
     }
 
-    public static final class Casts {
-        private static void description(CastBuilder casts) {
+    public static final class CastsHelper {
+        private static void description(Casts casts) {
             casts.arg("description").mustBe(stringValue()).asStringVector().shouldBe(singleElement(), RError.Message.ARGUMENT_ONLY_FIRST_1, "description").findFirst().notNA();
         }
 
-        private static HeadPhaseBuilder<String> open(CastBuilder casts) {
+        private static HeadPhaseBuilder<String> open(Casts casts) {
             return casts.arg("open").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().notNA();
         }
 
-        private static void encoding(CastBuilder casts) {
+        private static void encoding(Casts casts) {
             casts.arg("encoding").asStringVector().mustBe(singleElement()).findFirst();
         }
 
-        private static void raw(CastBuilder casts) {
+        private static void raw(Casts casts) {
             casts.arg("raw").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        private static void blocking(CastBuilder casts) {
+        private static void blocking(Casts casts) {
             casts.arg("blocking").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        public static void connection(CastBuilder casts) {
+        public static void connection(Casts casts) {
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         }
 
-        private static void nchars(CastBuilder casts) {
+        private static void nchars(Casts casts) {
             casts.arg("nchars").asIntegerVector().mustBe(notEmpty());
         }
 
-        private static void useBytes(CastBuilder casts) {
+        private static void useBytes(Casts casts) {
             casts.arg("useBytes").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        private static void n(CastBuilder casts) {
+        private static void n(Casts casts) {
             casts.arg("n").asIntegerVector().findFirst().mustBe(gte(0));
         }
 
-        private static void size(CastBuilder casts) {
+        private static void size(Casts casts) {
             casts.arg("size").asIntegerVector().findFirst();
         }
 
-        private static void swap(CastBuilder casts) {
+        private static void swap(Casts casts) {
             casts.arg("swap").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
-        private static void method(CastBuilder casts) {
+        private static void method(Casts casts) {
             casts.arg("method").asStringVector().findFirst();
         }
     }
@@ -187,14 +187,14 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "file", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding", "method", "raw"}, behavior = IO)
     public abstract static class File extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
-            Casts.open(casts);
+        static {
+            Casts casts = new Casts(File.class);
+            CastsHelper.description(casts);
+            CastsHelper.open(casts);
             casts.arg("blocking").asLogicalVector().findFirst().mustBe(logicalTrue(), RError.Message.NYI, "non-blocking mode not supported").map(toBoolean());
-            Casts.encoding(casts);
-            Casts.method(casts);
-            Casts.raw(casts);
+            CastsHelper.encoding(casts);
+            CastsHelper.method(casts);
+            CastsHelper.raw(casts);
         }
 
         @Specialization
@@ -236,12 +236,13 @@ public abstract class ConnectionFunctions {
             this.cType = cType;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
-            Casts.open(casts);
-            Casts.encoding(casts);
+        protected static Casts createCasts(Class<? extends ZZFileAdapter> extCls, RCompression.Type cType) {
+            Casts casts = new Casts(extCls);
+            CastsHelper.description(casts);
+            CastsHelper.open(casts);
+            CastsHelper.encoding(casts);
             casts.arg("compression").asIntegerVector().findFirst().notNA().mustBe(gte(cType == RCompression.Type.XZ ? -9 : 0).and(lte(9)));
+            return casts;
         }
 
         @Specialization
@@ -265,6 +266,10 @@ public abstract class ConnectionFunctions {
         protected GZFile() {
             super(RCompression.Type.GZIP);
         }
+
+        static {
+            createCasts(GZFile.class, RCompression.Type.GZIP);
+        }
     }
 
     @RBuiltin(name = "bzfile", kind = INTERNAL, parameterNames = {"description", "open", "encoding", "compression"}, behavior = IO)
@@ -272,6 +277,10 @@ public abstract class ConnectionFunctions {
         protected BZFile() {
             super(RCompression.Type.BZIP2);
         }
+
+        static {
+            createCasts(BZFile.class, RCompression.Type.BZIP2);
+        }
     }
 
     @RBuiltin(name = "xzfile", kind = INTERNAL, parameterNames = {"description", "open", "encoding", "compression"}, behavior = IO)
@@ -279,18 +288,23 @@ public abstract class ConnectionFunctions {
         protected XZFile() {
             super(RCompression.Type.XZ);
         }
+
+        static {
+            createCasts(XZFile.class, RCompression.Type.XZ);
+        }
     }
 
     @RBuiltin(name = "textConnection", kind = INTERNAL, parameterNames = {"description", "text", "open", "env", "encoding"}, behavior = IO)
     public abstract static class TextConnection extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
+
+        static {
+            Casts casts = new Casts(TextConnection.class);
+            CastsHelper.description(casts);
             // TODO how to have either a RNull or a String/RStringVector and have the latter coerced
             // to a
             // RAbstractStringVector to avoid the explicit handling in the specialization
             casts.arg("text").allowNull().mustBe(stringValue());
-            Casts.open(casts).mustBe(equalTo("").or(equalTo("r").or(equalTo("w").or(equalTo("a")))), RError.Message.UNSUPPORTED_MODE);
+            CastsHelper.open(casts).mustBe(equalTo("").or(equalTo("r").or(equalTo("w").or(equalTo("a")))), RError.Message.UNSUPPORTED_MODE);
             casts.arg("env").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
             casts.arg("encoding").asIntegerVector().findFirst().notNA();
         }
@@ -330,9 +344,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "textConnectionValue", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class TextConnectionValue extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("con").defaultError(Message.NOT_A_TEXT_CONNECTION).mustNotBeNull().mustBe(integerValue()).asIntegerVector().findFirst();
+
+        static {
+            Casts casts = new Casts(TextConnectionValue.class);
+            casts.arg("con").defaultError(Message.NOT_A_TEXT_CONNECTION).mustBe(integerValue()).asIntegerVector().findFirst();
         }
 
         @Specialization
@@ -350,13 +365,13 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "socketConnection", kind = INTERNAL, parameterNames = {"host", "port", "server", "blocking", "open", "encoding", "timeout"}, behavior = IO)
     public abstract static class SocketConnection extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SocketConnection.class);
             casts.arg("host").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("port").asIntegerVector().findFirst().notNA().mustBe(gte(0));
             casts.arg("server").asLogicalVector().findFirst().notNA().map(toBoolean());
-            Casts.open(casts);
-            Casts.blocking(casts);
+            CastsHelper.open(casts);
+            CastsHelper.blocking(casts);
             casts.arg("timeout").asIntegerVector().findFirst();
         }
 
@@ -379,13 +394,13 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "url", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding", "method"}, behavior = IO)
     public abstract static class URLConnection extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.description(casts);
-            Casts.open(casts);
-            Casts.blocking(casts);
-            Casts.encoding(casts);
-            Casts.method(casts);
+        static {
+            Casts casts = new Casts(URLConnection.class);
+            CastsHelper.description(casts);
+            CastsHelper.open(casts);
+            CastsHelper.blocking(casts);
+            CastsHelper.encoding(casts);
+            CastsHelper.method(casts);
         }
 
         @Specialization
@@ -407,8 +422,8 @@ public abstract class ConnectionFunctions {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"description", "class", "mode", "text", "opened", "can read", "can write"},
                         RDataFactory.COMPLETE_VECTOR);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Summary.class);
             casts.arg("object").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         }
 
@@ -431,11 +446,11 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "open", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "open", "blocking"}, behavior = IO)
     public abstract static class Open extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
-            Casts.open(casts);
-            Casts.blocking(casts);
+        static {
+            Casts casts = new Casts(Open.class);
+            CastsHelper.connection(casts);
+            CastsHelper.open(casts);
+            CastsHelper.blocking(casts);
         }
 
         @Specialization
@@ -460,9 +475,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "isOpen", kind = INTERNAL, parameterNames = {"con", "rw"}, behavior = IO)
     public abstract static class IsOpen extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(IsOpen.class);
+            CastsHelper.connection(casts);
             casts.arg("rw").asIntegerVector().findFirst();
         }
 
@@ -489,9 +505,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "close", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "type"}, behavior = IO)
     public abstract static class Close extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(Close.class);
+            CastsHelper.connection(casts);
             casts.arg("type").asStringVector().findFirst();
         }
 
@@ -511,13 +528,13 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "readLines", kind = INTERNAL, parameterNames = {"con", "n", "ok", "warn", "encoding", "skipNul"}, behavior = IO)
     public abstract static class ReadLines extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+        static {
+            Casts casts = new Casts(ReadLines.class);
+            CastsHelper.connection(casts);
             casts.arg("n").asIntegerVector().findFirst().notNA();
             casts.arg("ok").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("warn").asLogicalVector().findFirst().notNA().map(toBoolean());
-            Casts.encoding(casts);
+            CastsHelper.encoding(casts);
             casts.arg("skipNul").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
@@ -539,12 +556,13 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "writeLines", visibility = OFF, kind = INTERNAL, parameterNames = {"text", "con", "sep", "useBytes"}, behavior = IO)
     public abstract static class WriteLines extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(WriteLines.class);
             casts.arg("text").asStringVector().mustBe(instanceOf(RAbstractStringVector.class));
-            Casts.connection(casts);
+            CastsHelper.connection(casts);
             casts.arg("sep").asStringVector().findFirst();
-            Casts.useBytes(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @Specialization
@@ -561,9 +579,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "flush", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class Flush extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(Flush.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -581,10 +600,10 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "pushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"data", "con", "newLine", "type"}, behavior = IO)
     public abstract static class PushBack extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PushBack.class);
             casts.arg("data").asStringVector().mustBe(instanceOf(RAbstractStringVector.class));
-            Casts.connection(casts);
+            CastsHelper.connection(casts);
             casts.arg("newLine").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("type").asIntegerVector().findFirst();
         }
@@ -599,9 +618,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "pushBackLength", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class PushBackLength extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(PushBackLength.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -613,9 +633,9 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "clearPushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
     public abstract static class PushBackClear extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+        static {
+            Casts casts = new Casts(PushBackClear.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -628,11 +648,11 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "readChar", kind = INTERNAL, parameterNames = {"con", "nchars", "useBytes"}, behavior = IO)
     public abstract static class ReadChar extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
-            Casts.nchars(casts);
-            Casts.useBytes(casts);
+        static {
+            Casts casts = new Casts(ReadChar.class);
+            CastsHelper.connection(casts);
+            CastsHelper.nchars(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @SuppressWarnings("unused")
@@ -662,14 +682,15 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "writeChar", visibility = OFF, kind = INTERNAL, parameterNames = {"object", "con", "nchars", "sep", "useBytes"}, behavior = IO)
     public abstract static class WriteChar extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(WriteChar.class);
             casts.arg("object").asStringVector();
-            casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().mustBe(integerValue().or(rawValue())).mapIf(integerValue(),
+            casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustBe(integerValue().or(rawValue())).mapIf(integerValue(),
                             asIntegerVector().setNext(findFirst().integerElement()));
-            Casts.nchars(casts);
+            CastsHelper.nchars(casts);
             casts.arg("sep").allowNull().mustBe(stringValue());
-            Casts.useBytes(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @TruffleBoundary
@@ -717,15 +738,15 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "readBin", kind = INTERNAL, parameterNames = {"con", "what", "n", "size", "signed", "swap"}, behavior = IO)
     public abstract static class ReadBin extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ReadBin.class);
             // TODO con can be a RAWSXP (not implemented)
-            Casts.connection(casts);
+            CastsHelper.connection(casts);
             casts.arg("what").asStringVector().findFirst();
-            Casts.n(casts);
-            Casts.size(casts);
+            CastsHelper.n(casts);
+            CastsHelper.size(casts);
             casts.arg("signed").asLogicalVector().findFirst().notNA().map(toBoolean());
-            Casts.swap(casts);
+            CastsHelper.swap(casts);
         }
 
         @Specialization
@@ -1003,14 +1024,14 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "writeBin", visibility = OFF, kind = INTERNAL, parameterNames = {"object", "con", "size", "swap", "useBytes"}, behavior = IO)
     public abstract static class WriteBin extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(WriteBin.class);
             // TODO atomic, i.e. not RList or RExpression
             casts.arg("object").asVector().mustBe(instanceOf(RAbstractVector.class));
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustBe(integerValue().or(rawValue())).mapIf(integerValue(), asIntegerVector().setNext(findFirst().integerElement()));
-            Casts.size(casts);
-            Casts.swap(casts);
-            Casts.useBytes(casts);
+            CastsHelper.size(casts);
+            CastsHelper.swap(casts);
+            CastsHelper.useBytes(casts);
         }
 
         @TruffleBoundary
@@ -1050,8 +1071,8 @@ public abstract class ConnectionFunctions {
     @RBuiltin(name = "getConnection", kind = INTERNAL, parameterNames = {"what"}, behavior = IO)
     public abstract static class GetConnection extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GetConnection.class);
             casts.arg("what").asIntegerVector().findFirst();
         }
 
@@ -1078,9 +1099,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "isSeekable", kind = INTERNAL, parameterNames = "con", behavior = IO)
     public abstract static class IsSeekable extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(IsSeekable.class);
+            CastsHelper.connection(casts);
         }
 
         @Specialization
@@ -1092,9 +1114,10 @@ public abstract class ConnectionFunctions {
 
     @RBuiltin(name = "seek", kind = INTERNAL, parameterNames = {"con", "where", "origin", "rw"}, behavior = IO)
     public abstract static class Seek extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.connection(casts);
+
+        static {
+            Casts casts = new Casts(Seek.class);
+            CastsHelper.connection(casts);
             casts.arg("where").asDoubleVector().findFirst();
             casts.arg("origin").asIntegerVector().findFirst();
             casts.arg("rw").asIntegerVector().findFirst();
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 491c440ba79dbbd197522d28fb8ce694809b9ff9..d9f2875e1ccb591a09aae6c1cad02f67cb05d411 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +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 {
 
+    static {
+        Casts.noCasts(CopyDFAttr.class);
+    }
+
     @Specialization()
     protected RAttributable copy(RAbstractContainer in, RAbstractVector out) {
         RVector<?> res = out.materialize();
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 01f77b91cb8a9ebb250b6e31698a7203d1e616b5..842176d6551cdf07ca9ad504d101c6bb22b1757f 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
@@ -33,7 +33,6 @@ 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;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -48,8 +47,8 @@ public abstract class Crossprod extends RBuiltinNode {
     @Child private MatMult matMult = MatMultNodeGen.create(/* promoteDimNames: */ false);
     @Child private Transpose transpose;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Crossprod.class);
         casts.arg("x").mustBe(numericValue().or(complexValue()), RError.ROOTNODE, RError.Message.NUMERIC_COMPLEX_MATRIX_VECTOR);
         casts.arg("y").defaultError(RError.ROOTNODE, RError.Message.NUMERIC_COMPLEX_MATRIX_VECTOR).allowNull().mustBe(numericValue().or(complexValue()));
     }
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 708b1ab7175ac9ec65b11ae534c40b12e53e474d..236988ed4697a42c9593a61552bdb30ff7c32f3d 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
@@ -25,7 +25,6 @@ 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;
@@ -47,8 +46,8 @@ public abstract class CumMax extends RBuiltinNode {
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumMax.class);
         casts.arg("x").allowNull().mustBe(complexValue().not(), RError.Message.CUMMAX_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(true, false, false),
                         asDoubleVector(true, false, false));
     }
@@ -119,7 +118,7 @@ public abstract class CumMax extends RBuiltinNode {
         return RDataFactory.createDoubleVector(cmaxV, na.neverSeenNA(), getNamesNode.getNames(v));
     }
 
-    @Specialization(contains = "cummaxIntSequence")
+    @Specialization(replaces = "cummaxIntSequence")
     protected RIntVector cummax(RAbstractIntVector v) {
         int[] cmaxV = new int[v.getLength()];
         na.enable(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 4a050a9f594aae6ac723cf0697741ed34eb3b6ce..ae28196a601f003886b7738af55b3c9bfe41a2a1 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
@@ -25,7 +25,6 @@ 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;
@@ -47,8 +46,8 @@ public abstract class CumMin extends RBuiltinNode {
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumMin.class);
         casts.arg("x").allowNull().mustBe(complexValue().not(), RError.Message.CUMMIN_UNDEFINED_FOR_COMPLEX).mapIf(integerValue().or(logicalValue()), asIntegerVector(true, false, false),
                         asDoubleVector(true, false, false));
     }
@@ -119,7 +118,7 @@ public abstract class CumMin extends RBuiltinNode {
         return RDataFactory.createDoubleVector(cminV, na.neverSeenNA(), getNamesNode.getNames(v));
     }
 
-    @Specialization(contains = "cumminIntSequence")
+    @Specialization(replaces = "cumminIntSequence")
     protected RIntVector cummin(RAbstractIntVector v) {
         int[] cminV = new int[v.getLength()];
         na.enable(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 20dcf0d352f48b882e8b8647c7df88148d5d2269..ef609bb01119c116b02ced24964414134ca960ac 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
@@ -20,7 +20,6 @@ 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;
@@ -43,8 +42,8 @@ public abstract class CumProd extends RBuiltinNode {
 
     @Child private BinaryArithmetic mul = BinaryArithmetic.MULTIPLY.createOperation();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumProd.class);
         casts.arg("x").allowNull().mapIf(complexValue().not(), asDoubleVector(true, false, false));
     }
 
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 92649d60d5859fa40764a4b7a5322bfe26eb14d4..7a1886ac6ee122a9b987e4959dada87ca123bcfa 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
@@ -37,7 +37,6 @@ 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;
@@ -63,8 +62,8 @@ public abstract class CumSum extends RBuiltinNode {
 
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CumSum.class);
         casts.arg("x").allowNull().mapIf(integerValue().or(logicalValue()), asIntegerVector(true, false, false), chain(mapIf(complexValue().not(), asDoubleVector(true, false, false))).end());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java
index f3621cd18b11f21d9f71fcad1e2884c95381103d..8a7255109242749be6f443c5dc4f98131ede3bbc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RDeparse;
 import com.oracle.truffle.r.runtime.RError;
@@ -44,8 +43,8 @@ import com.oracle.truffle.r.runtime.conn.RConnection;
 @RBuiltin(name = "dput", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "file", "opts"}, behavior = IO)
 public abstract class DPut extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DPut.class);
         casts.arg("file").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         casts.arg("opts").asIntegerVector().findFirst();
     }
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 8709521c226523cb7b6e9f1f64463ff6f4745378..f5ea8c6b09eca0a406161cac73c4fa708cfb6b22 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
@@ -40,7 +40,6 @@ 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;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -140,8 +139,8 @@ public class DatePOSIXFunctions {
 
         @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Date2POSIXlt.class);
             casts.arg("x").mapNull(emptyDoubleVector()).asDoubleVector();
         }
 
@@ -176,8 +175,8 @@ public class DatePOSIXFunctions {
 
         @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AsPOSIXlt.class);
             casts.arg("x").mapNull(emptyDoubleVector()).asDoubleVector(true, false, false);
             casts.arg("tz").asStringVector().findFirst("");
         }
@@ -216,8 +215,8 @@ public class DatePOSIXFunctions {
     @RBuiltin(name = "as.POSIXct", kind = INTERNAL, parameterNames = {"x", "tz"}, behavior = READS_STATE)
     public abstract static class AsPOSIXct extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AsPOSIXct.class);
             casts.arg("x").mustBe(RAbstractListVector.class);
             casts.arg("tz").asStringVector().findFirst("");
         }
@@ -275,8 +274,8 @@ public class DatePOSIXFunctions {
     public abstract static class POSIXlt2Date extends RBuiltinNode {
         private static final RStringVector CLASS_ATTR = (RStringVector) RDataFactory.createStringVectorFromScalar("Date").makeSharedPermanent();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(POSIXlt2Date.class);
             casts.arg("x").mustBe(RAbstractListVector.class);
         }
 
@@ -333,8 +332,8 @@ public class DatePOSIXFunctions {
             // TODO: find a proper source for this mapping
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FormatPOSIXlt.class);
             casts.arg("x").mustBe(RAbstractListVector.class);
             casts.arg("format").asStringVector().mustBe(notEmpty());
             casts.arg("usetz").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
@@ -391,8 +390,8 @@ public class DatePOSIXFunctions {
     @RBuiltin(name = "strptime", kind = INTERNAL, parameterNames = {"x", "format", "tz"}, behavior = PURE)
     public abstract static class StrPTime extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(StrPTime.class);
             casts.arg("x").mapNull(emptyStringVector()).asStringVector();
             casts.arg("format").mapNull(emptyStringVector()).asStringVector();
             casts.arg("tz").mapNull(emptyStringVector()).asStringVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
index a4ed591f4a180e85358173bb53b0c57a4346d00d..c6f3bba7160fdb8272df5c92127563eba3f7166c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.nodes.builtin.helpers.DebugHandling;
 import com.oracle.truffle.r.runtime.RError;
@@ -43,9 +42,10 @@ public class DebugFunctions {
 
     protected abstract static class ErrorAndFunAdapter extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        protected static Casts createCasts(Class<? extends ErrorAndFunAdapter> extCls) {
+            Casts casts = new Casts(extCls);
             casts.arg("fun").mustBe(RFunction.class, Message.ARG_MUST_BE_CLOSURE);
+            return casts;
         }
 
         protected void doDebug(RFunction fun, Object text, Object condition, boolean once) throws RError {
@@ -61,6 +61,10 @@ public class DebugFunctions {
     @RBuiltin(name = "debug", visibility = OFF, kind = INTERNAL, parameterNames = {"fun", "text", "condition"}, behavior = COMPLEX)
     public abstract static class Debug extends ErrorAndFunAdapter {
 
+        static {
+            createCasts(Debug.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull doDebug(RFunction fun, Object text, Object condition) {
@@ -72,6 +76,10 @@ public class DebugFunctions {
     @RBuiltin(name = "debugonce", visibility = OFF, kind = INTERNAL, parameterNames = {"fun", "text", "condition"}, behavior = COMPLEX)
     public abstract static class DebugOnce extends ErrorAndFunAdapter {
 
+        static {
+            createCasts(DebugOnce.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull debugonce(RFunction fun, Object text, Object condition) {
@@ -84,6 +92,10 @@ public class DebugFunctions {
     @RBuiltin(name = "undebug", visibility = OFF, kind = INTERNAL, parameterNames = {"fun"}, behavior = COMPLEX)
     public abstract static class UnDebug extends ErrorAndFunAdapter {
 
+        static {
+            createCasts(UnDebug.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull undebug(RFunction func) {
@@ -97,6 +109,10 @@ public class DebugFunctions {
     @RBuiltin(name = "isdebugged", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
     public abstract static class IsDebugged extends ErrorAndFunAdapter {
 
+        static {
+            createCasts(IsDebugged.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected byte isDebugged(RFunction func) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java
index defed06f112de37f4d93a3230c7e94f81f9a9fc9..6db3144a985f4b5e0db857ba8b6aca1614d50193 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DelayedAssign.java
@@ -33,7 +33,6 @@ 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.RASTUtils;
-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.builtins.RBuiltin;
@@ -49,8 +48,8 @@ public abstract class DelayedAssign extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DelayedAssign.class);
         casts.arg("x").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.INVALID_FIRST_ARGUMENT).findFirst();
         casts.arg("eval.env").mustNotBeNull(RError.SHOW_CALLER, RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
         casts.arg("assign.env").mustNotBeNull(RError.SHOW_CALLER, RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java
index 8fb0d1ffbe14d540b1957761085e9368f164a9dd..e1abc2461e3fb24e568e8b3381d71c5469c2585a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RDeparse;
 import com.oracle.truffle.r.runtime.RError;
@@ -31,8 +30,8 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 @RBuiltin(name = "deparse", kind = INTERNAL, parameterNames = {"expr", "width.cutoff", "backtick", "control", "nlines"}, behavior = PURE)
 public abstract class Deparse extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Deparse.class);
         casts.arg("width.cutoff").asIntegerVector().findFirst(0);
         casts.arg("backtick").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
         casts.arg("control").asIntegerVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
index b8130992c80cc11e3786415aff64f48aa678dd0d..6ddd7cabaf0a63f137a4dea068a2dfaeadcce128 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1998-2013, The R Core Team
  * Copyright (c) 2003-2015, The R Foundation
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -21,7 +21,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
 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.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 @RBuiltin(name = "diag", kind = INTERNAL, parameterNames = {"x", "nrow", "ncol"}, behavior = PURE)
 public abstract class Diag extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Diag.class);
         casts.arg("x").allowNull().mapIf(complexValue().not(), asDoubleVector());
 
         casts.arg("nrow").asIntegerVector().findFirst().mustBe(notIntNA(), Message.INVALID_LARGE_NA_VALUE, "nrow").mustBe(gte0(), Message.INVALID_NEGATIVE_VALUE, "nrow");
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 f9af807d25e52c27151f9c6437185a71c28e7762..9e495172e5ddfa9b633c73da7eaff65ecf8fc582 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
@@ -39,6 +39,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 @RBuiltin(name = "dim", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class Dim extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Dim.class);
+    }
+
     @Specialization
     protected Object dim(RAbstractContainer container,
                     @Cached("createBinaryProfile()") ConditionProfile hasDimensionsProfile,
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 0de9caa23a61d369a9b1b29fd250c4c87f07e3f5..2993a023e58813ab9b89c0b08244068e5eaf09ad 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
@@ -41,6 +41,10 @@ public abstract class DimNames extends RBuiltinNode {
 
     private final ConditionProfile nullProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(DimNames.class);
+    }
+
     @Specialization(guards = "!isRAbstractContainer(operand)")
     protected RNull getDimNames(@SuppressWarnings("unused") Object operand) {
         return RNull.instance;
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 746a892680cd7f6674d955dd2c501a1d1b290e4c..9976ccbaa8c3addfb04bec75e50d1f3757b4eaef 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,21 +32,16 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 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.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.GetFunctions.Get;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen;
-import com.oracle.truffle.r.nodes.function.GetCallerFrameNode;
-import com.oracle.truffle.r.nodes.function.RCallBaseNode;
-import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -77,18 +72,15 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 @RBuiltin(name = "do.call", visibility = CUSTOM, kind = RBuiltinKind.SUBSTITUTE, parameterNames = {"what", "args", "quote", "envir"}, behavior = COMPLEX)
 public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNodeChildren {
 
-    @Child private GetCallerFrameNode getCallerFrame;
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
     private final BranchProfile containsRLanguageProfile = BranchProfile.create();
     private final BranchProfile containsRSymbolProfile = BranchProfile.create();
 
-    private final Object argsIdentifier = new Object();
-    @Child private RCallBaseNode call = RCallNode.createExplicitCall(argsIdentifier);
-    @Child private FrameSlotNode slot = FrameSlotNode.createTemp(argsIdentifier, true);
+    @Child private RExplicitCallNode call = RExplicitCallNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(DoCall.class);
         casts.arg("what").defaultError(Message.MUST_BE_STRING_OR_FUNCTION, "what").mustBe(instanceOf(RFunction.class).or(stringValue()));
         casts.arg("args").mustBe(RAbstractListVector.class, Message.SECOND_ARGUMENT_LIST);
         casts.arg("quote").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
@@ -125,7 +117,7 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
         return doCall(frame, func, argsAsList, quote, env);
     }
 
-    @Specialization(contains = "doCallCached")
+    @Specialization(replaces = "doCallCached")
     protected Object doCall(VirtualFrame frame, RAbstractStringVector what, RList argsAsList, boolean quote, RMissing env) {
         if (what.getLength() != 1) {
             CompilerDirectives.transferToInterpreter();
@@ -171,13 +163,7 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
                 }
             }
         }
-        FrameSlot frameSlot = slot.executeFrameSlot(frame);
-        try {
-            frame.setObject(frameSlot, new RArgsValuesAndNames(argValues, signature));
-            return call.execute(frame, func);
-        } finally {
-            frame.setObject(frameSlot, null);
-        }
+        return call.execute(frame, func, new RArgsValuesAndNames(argValues, signature));
     }
 
     @TruffleBoundary
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 5edaedbcbe3deb34d6e44342fde765197ca61fee..295782ffeddd39e036218c3ec8828e504f35691d 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
@@ -50,6 +50,10 @@ public abstract class Drop extends RBuiltinNode {
     private final ConditionProfile resultIsScalarProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile noDimNamesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Drop.class);
+    }
+
     @Specialization
     protected RAbstractVector doDrop(RAbstractVector x,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java
index d137a43dd3201dd02b3b54b718642402b75f0997..79f201063c8527f804895e203f09c65f5b8c32c7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DuplicatedFunctions.java
@@ -22,7 +22,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
@@ -46,7 +45,7 @@ public class DuplicatedFunctions {
 
         private final ConditionProfile incomparable = ConditionProfile.createBinaryProfile();
 
-        protected void casts(CastBuilder casts) {
+        protected static void casts(Casts casts) {
             // these are similar to those in DuplicatedFunctions.java
             casts.arg("x").mapNull(emptyList()).mustBe(abstractVectorValue(), RError.SHOW_CALLER,
                             RError.Message.APPLIES_TO_VECTORS,
@@ -85,8 +84,8 @@ public class DuplicatedFunctions {
     @RBuiltin(name = "duplicated", kind = INTERNAL, parameterNames = {"x", "incomparables", "fromLast", "nmax"}, behavior = PURE)
     public abstract static class Duplicated extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Duplicated.class);
             casts(casts);
             // currently not supported and not tested, but NA is a correct value (the same for empty
             // vectors) whereas 0 is not (throws an error)
@@ -132,8 +131,8 @@ public class DuplicatedFunctions {
     @RBuiltin(name = "anyDuplicated", kind = INTERNAL, parameterNames = {"x", "incomparables", "fromLast"}, behavior = PURE)
     public abstract static class AnyDuplicated extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AnyDuplicated.class);
             casts(casts);
         }
 
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 2d29673449b4527b3914687f694f5e2e6c106058..688dd47a2c24c7b206eb193eb929fc91085cde1b 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
@@ -35,12 +35,11 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import java.util.ArrayList;
 
 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.SetClassAttributeNode;
-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.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -62,8 +61,8 @@ public class DynLoadFunctions {
     public abstract static class DynLoad extends RBuiltinNode {
         @Child private DLL.LoadPackageDLLNode loadPackageDLLNode = DLL.LoadPackageDLLNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DynLoad.class);
             casts.arg("lib").mustBe(stringValue()).asStringVector().mustBe(size(1), RError.Message.CHAR_ARGUMENT).findFirst();
             casts.arg("local").asLogicalVector().findFirst().map(toBoolean());
             casts.arg("now").asLogicalVector().findFirst().map(toBoolean());
@@ -74,21 +73,20 @@ public class DynLoadFunctions {
         @TruffleBoundary
         protected RList doDynLoad(String lib, boolean local, boolean now, @SuppressWarnings("unused") String unused) {
             try {
-                DLLInfo dllInfo = loadPackageDLLNode.loadPackageDLL(lib, local, now);
+                DLLInfo dllInfo = loadPackageDLLNode.execute(lib, local, now);
                 return dllInfo.toRList();
             } catch (DLLException ex) {
-                // This is not a recoverable error
-                System.out.println("exception while loading " + lib + ":");
-                ex.printStackTrace();
-                throw RInternalError.shouldNotReachHere(ex);
+                throw RError.error(RError.SHOW_CALLER, ex);
             }
         }
     }
 
     @RBuiltin(name = "dyn.unload", visibility = OFF, kind = INTERNAL, parameterNames = {"lib"}, behavior = COMPLEX)
     public abstract static class DynUnload extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        @Child DLL.UnloadNode dllUnloadNode = DLL.UnloadNode.create();
+
+        static {
+            Casts casts = new Casts(DynUnload.class);
             casts.arg("lib").mustBe(stringValue()).asStringVector().mustBe(size(1), RError.Message.CHAR_ARGUMENT).findFirst();
         }
 
@@ -96,7 +94,7 @@ public class DynLoadFunctions {
         @TruffleBoundary
         protected RNull doDynunload(RAbstractStringVector lib) {
             try {
-                DLL.unload(lib.getDataAt(0));
+                dllUnloadNode.execute(lib.getDataAt(0));
             } catch (DLLException ex) {
                 throw RError.error(this, ex);
             }
@@ -129,8 +127,10 @@ public class DynLoadFunctions {
 
     @RBuiltin(name = "is.loaded", kind = INTERNAL, parameterNames = {"symbol", "PACKAGE", "type"}, behavior = READS_STATE)
     public abstract static class IsLoaded extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
+
+        static {
+            Casts casts = new Casts(IsLoaded.class);
             casts.arg("symbol").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
             casts.arg("PACKAGE").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
             casts.arg("type").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
@@ -156,15 +156,17 @@ public class DynLoadFunctions {
                     // Not an error in GnuR
             }
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(nst, null, null);
-            boolean found = DLL.findSymbol(symbol, packageName, rns) != DLL.SYMBOL_NOT_FOUND;
+            boolean found = findSymbolNode.execute(symbol, packageName, rns) != DLL.SYMBOL_NOT_FOUND;
             return RRuntime.asLogical(found);
         }
     }
 
     @RBuiltin(name = "getSymbolInfo", kind = INTERNAL, parameterNames = {"symbol", "package", "withRegistrationInfo"}, behavior = READS_STATE)
     public abstract static class GetSymbolInfo extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
+
+        static {
+            Casts casts = new Casts(GetSymbolInfo.class);
             casts.arg("symbol").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
             casts.arg("withRegistrationInfo").mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean());
         }
@@ -173,7 +175,7 @@ public class DynLoadFunctions {
         @TruffleBoundary
         protected Object getSymbolInfo(String symbol, String packageName, boolean withReg) {
             DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
-            DLL.SymbolHandle f = DLL.findSymbol(RRuntime.asString(symbol), packageName, rns);
+            DLL.SymbolHandle f = findSymbolNode.execute(RRuntime.asString(symbol), packageName, rns);
             SymbolInfo symbolInfo = null;
             if (f != DLL.SYMBOL_NOT_FOUND) {
                 symbolInfo = new SymbolInfo(rns.getDllInfo(), symbol, f);
@@ -183,7 +185,8 @@ public class DynLoadFunctions {
 
         @Specialization(guards = "isDLLInfo(externalPtr)")
         @TruffleBoundary
-        protected Object getSymbolInfo(RAbstractStringVector symbolVec, RExternalPtr externalPtr, boolean withReg) {
+        protected Object getSymbolInfo(RAbstractStringVector symbolVec, RExternalPtr externalPtr, boolean withReg, //
+                        @Cached("create()") DLL.RdlsymNode dlsymNode) {
             DLL.DLLInfo dllInfo = (DLLInfo) externalPtr.getExternalObject();
             if (dllInfo == null) {
                 throw RError.error(this, RError.Message.REQUIRES_NAME_DLLINFO);
@@ -191,7 +194,7 @@ public class DynLoadFunctions {
 
             DLL.RegisteredNativeSymbol rns = DLL.RegisteredNativeSymbol.any();
             String symbol = symbolVec.getDataAt(0);
-            DLL.SymbolHandle f = DLL.dlsym(dllInfo, RRuntime.asString(symbol), rns);
+            DLL.SymbolHandle f = dlsymNode.execute(dllInfo, RRuntime.asString(symbol), rns);
             SymbolInfo symbolInfo = null;
             if (f != DLL.SYMBOL_NOT_FOUND) {
                 symbolInfo = new SymbolInfo(dllInfo, symbol, f);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java
index 929833c85db81011d1549b1da642863bad781377..2cdec5a98cd8b5e42dffc9cff0b8dfe6c72a0ef1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodeString.java
@@ -24,7 +24,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -49,8 +48,8 @@ public abstract class EncodeString extends RBuiltinNode {
     private final NACheck na = NACheck.create();
     private final BranchProfile everSeenNA = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(EncodeString.class);
         casts.arg("x").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
 
         casts.arg("width").asIntegerVector().findFirst().mustBe(intNA().or(gte0()));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java
index 9e6d68c9d4c68752bb3aefbe97a02b8b438172a1..9b05c97603454440b261b60deb0efcca08517372 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EncodingFunctions.java
@@ -28,7 +28,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -40,8 +39,9 @@ public class EncodingFunctions {
 
     @RBuiltin(name = "Encoding", kind = INTERNAL, parameterNames = "x", behavior = PURE)
     public abstract static class Encoding extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Encoding.class);
             casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.CHAR_VEC_ARGUMENT);
         }
 
@@ -54,8 +54,9 @@ public class EncodingFunctions {
 
     @RBuiltin(name = "setEncoding", kind = INTERNAL, parameterNames = {"x", "value"}, behavior = PURE)
     public abstract static class SetEncoding extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SetEncoding.class);
             casts.arg("x").defaultError(RError.SHOW_CALLER, RError.Message.CHAR_VEC_ARGUMENT).mustBe(stringValue());
             // asStringVector is required for notEmpty() to receive a proper type in case of scalars
             casts.arg("value").defaultError(RError.SHOW_CALLER, RError.Message.GENERIC, "a character vector 'value' expected").mustBe(stringValue()).asStringVector().mustBe(notEmpty(),
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 a8fd09929618f8524cb481bf48a27ced1206838d..f71df176ee575c5d9ef4763d9cfae8d4ff430b3b 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
@@ -50,7 +50,6 @@ 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;
 import com.oracle.truffle.r.nodes.builtin.base.EnvFunctionsFactory.CopyNodeGen;
@@ -95,8 +94,8 @@ public class EnvFunctions {
     @RBuiltin(name = "as.environment", kind = PRIMITIVE, parameterNames = {"fun"}, dispatch = INTERNAL_GENERIC, behavior = COMPLEX)
     public abstract static class AsEnvironment extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AsEnvironment.class);
             casts.arg("fun").mapIf(numericValue(), asIntegerVector());
         }
 
@@ -231,6 +230,10 @@ public class EnvFunctions {
     @RBuiltin(name = "topenv", kind = INTERNAL, parameterNames = {"envir", "matchThisEnv"}, behavior = COMPLEX)
     public abstract static class TopEnv extends Adapter {
 
+        static {
+            Casts.noCasts(TopEnv.class);
+        }
+
         @Child private FrameFunctions.ParentFrame parentFrameNode;
 
         @Specialization
@@ -281,8 +284,8 @@ public class EnvFunctions {
     @RBuiltin(name = "parent.env", kind = INTERNAL, parameterNames = {"env"}, behavior = READS_FRAME)
     public abstract static class ParentEnv extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ParentEnv.class);
             casts.arg("env").mustBe(instanceOf(REnvironment.class), RError.SHOW_CALLER, Message.ARGUMENT_NOT_ENVIRONMENT);
         }
 
@@ -299,8 +302,8 @@ public class EnvFunctions {
     @RBuiltin(name = "parent.env<-", kind = INTERNAL, parameterNames = {"env", "value"}, behavior = COMPLEX)
     public abstract static class SetParentEnv extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SetParentEnv.class);
             casts.arg("env").mustBe(instanceOf(REnvironment.class), Message.NON_LANG_ASSIGNMENT_TARGET);
             casts.arg("value").mustNotBeNull(Message.USE_NULL_ENV_DEFUNCT, "NULL").mustBe(instanceOf(REnvironment.class), Message.ARGUMENT_NAME_NOT_ENVIRONMENT, "parent");
         }
@@ -319,6 +322,10 @@ public class EnvFunctions {
     @RBuiltin(name = "is.environment", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsEnvironment extends RBuiltinNode {
 
+        static {
+            Casts.noCasts(IsEnvironment.class);
+        }
+
         @Specialization
         protected byte isEnvironment(Object env) {
             return env instanceof REnvironment ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE;
@@ -331,6 +338,10 @@ public class EnvFunctions {
         private final ConditionProfile attributable = ConditionProfile.createBinaryProfile();
         @Child private GetFixedAttributeNode getEnvAttrNode;
 
+        static {
+            Casts.noCasts(Environment.class);
+        }
+
         @Specialization
         protected Object environment(VirtualFrame frame, @SuppressWarnings("unused") RNull fun,
                         @Cached("new()") GetCallerFrameNode callerFrame,
@@ -390,8 +401,8 @@ public class EnvFunctions {
     @RBuiltin(name = "environment<-", kind = PRIMITIVE, parameterNames = {"env", "value"}, behavior = COMPLEX)
     public abstract static class UpdateEnvironment extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(UpdateEnvironment.class);
             casts.arg("value").allowNull().mustBe(REnvironment.class, Message.REPLACEMENT_NOT_ENVIRONMENT);
         }
 
@@ -464,6 +475,10 @@ public class EnvFunctions {
     @RBuiltin(name = "environmentName", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
     public abstract static class EnvironmentName extends RBuiltinNode {
 
+        static {
+            Casts.noCasts(EnvironmentName.class);
+        }
+
         @Specialization
         protected String environmentName(REnvironment env) {
             return env.getName();
@@ -479,10 +494,10 @@ public class EnvFunctions {
     @RBuiltin(name = "new.env", kind = INTERNAL, parameterNames = {"hash", "parent", "size"}, behavior = COMPLEX)
     public abstract static class NewEnv extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(NewEnv.class);
             casts.arg("hash").mustNotBeNull().asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
-            casts.arg("parent").mustNotBeNull().mustBe(REnvironment.class, Message.MUST_BE_ENVIRON);
+            casts.arg("parent").mustBe(REnvironment.class, Message.MUST_BE_ENVIRON);
             casts.arg("size").mustNotBeNull().asIntegerVector().findFirst(0);
         }
 
@@ -506,11 +521,11 @@ public class EnvFunctions {
     @RBuiltin(name = "lockEnvironment", visibility = OFF, kind = INTERNAL, parameterNames = {"env", "bindings"}, behavior = COMPLEX)
     public abstract static class LockEnvironment extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("env").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(LockEnvironment.class);
+            casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
             // TODO: the actual interpretation of this parameter remains dubious
-            casts.arg("bindings").mustNotBeNull().asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+            casts.arg("bindings").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         }
 
         @Specialization
@@ -523,9 +538,9 @@ public class EnvFunctions {
     @RBuiltin(name = "environmentIsLocked", kind = INTERNAL, parameterNames = {"env"}, behavior = PURE)
     public abstract static class EnvironmentIsLocked extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("env").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(EnvironmentIsLocked.class);
+            casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
 
         @Specialization
@@ -537,10 +552,10 @@ public class EnvFunctions {
     @RBuiltin(name = "lockBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = COMPLEX)
     public abstract static class LockBinding extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("sym").mustNotBeNull().mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
-            casts.arg("env").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(LockBinding.class);
+            casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
+            casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
 
         @Specialization
@@ -553,10 +568,10 @@ public class EnvFunctions {
     @RBuiltin(name = "unlockBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = COMPLEX)
     public abstract static class UnlockBinding extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("sym").mustNotBeNull().mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
-            casts.arg("env").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(UnlockBinding.class);
+            casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
+            casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
 
         @Specialization
@@ -569,10 +584,10 @@ public class EnvFunctions {
     @RBuiltin(name = "bindingIsLocked", kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = PURE)
     public abstract static class BindingIsLocked extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("sym").mustNotBeNull().mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
-            casts.arg("env").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(BindingIsLocked.class);
+            casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
+            casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
 
         @Specialization
@@ -584,11 +599,11 @@ public class EnvFunctions {
     @RBuiltin(name = "makeActiveBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "fun", "env"}, behavior = COMPLEX)
     public abstract static class MakeActiveBinding extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("sym").mustNotBeNull().mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
-            casts.arg("fun").mustNotBeNull().mustBe(RFunction.class, RError.SHOW_CALLER, Message.NOT_A_FUNCTION);
-            casts.arg("env").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(MakeActiveBinding.class);
+            casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
+            casts.arg("fun").mustBe(RFunction.class, RError.SHOW_CALLER, Message.NOT_A_FUNCTION);
+            casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
 
         @SuppressWarnings("unused")
@@ -602,10 +617,10 @@ public class EnvFunctions {
     @RBuiltin(name = "bindingIsActive", kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = PURE)
     public abstract static class BindingIsActive extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("sym").mustNotBeNull().mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
-            casts.arg("env").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(BindingIsActive.class);
+            casts.arg("sym").mustBe(RSymbol.class, RError.SHOW_CALLER, Message.NOT_A_SYMBOL);
+            casts.arg("env").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
         }
 
         @SuppressWarnings("unused")
@@ -621,9 +636,9 @@ public class EnvFunctions {
 
         @Child private CopyNode copy;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("x").mustNotBeNull().mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
+        static {
+            Casts casts = new Casts(EnvToList.class);
+            casts.arg("x").mustBe(REnvironment.class, RError.SHOW_CALLER, Message.NOT_AN_ENVIRONMENT);
             casts.arg("all.names").mustNotBeNull().asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
             casts.arg("sorted").mustNotBeNull().asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java
index aba09031a868723789bc7c17e3b7efdd2c8c5736..3367d84ad0838348813259ff5493955ce0d695d6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java
@@ -37,7 +37,6 @@ 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.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.EvalNodeGen.EvalEnvCastNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.FrameFunctions.SysFrame;
@@ -134,13 +133,11 @@ public abstract class Eval extends RBuiltinNode {
     @Child private EvalEnvCast envCast = EvalEnvCastNodeGen.create();
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
-        casts.arg("envir").allowNull().mustBe(instanceOf(REnvironment.class).or(instanceOf(RList.class)).or(instanceOf(RPairList.class)).or(numericValue())).
-                mapIf(numericValue(), chain(asIntegerVector()).with(mustBe(singleElement())).with(findFirst().integerElement()).end());
+    static {
+        Casts casts = new Casts(Eval.class);
+        casts.arg("envir").allowNull().mustBe(instanceOf(REnvironment.class).or(instanceOf(RList.class)).or(instanceOf(RPairList.class)).or(numericValue())).mapIf(numericValue(),
+                        chain(asIntegerVector()).with(mustBe(singleElement())).with(findFirst().integerElement()).end());
         casts.arg("enclos").allowNull().mustBe(REnvironment.class);
-        // @formatter:on
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
index e70b055c123b0f7e907fa223ab80bec3434eba1b..f08f18daa3dc3478474890ca9636265be26f71f3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Exists.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -52,8 +51,8 @@ public abstract class Exists extends RBuiltinNode {
      */
     public abstract byte execute(String nameVec, REnvironment env, String mode, boolean inherits);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Exists.class);
         casts.arg("x").mustBe(stringValue(), Message.INVALID_FIRST_ARGUMENT).asStringVector().findFirst();
         casts.arg("envir").mustBe(REnvironment.class);
         casts.arg("mode").mustBe(stringValue()).asStringVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
index a0c481ef01afc35a7d93f9f1309407fd2debe721..f4b9d0c8e54fa4bd3fc9f9798019d4f8278b0496 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,10 @@ public abstract class Expression extends RBuiltinNode {
      */
     private final ConditionProfile isEvaluatedProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Expression.class);
+    }
+
     @Specialization
     @ExplodeLoop
     protected Object doExpression(RArgsValuesAndNames args) {
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 3dd5c7dd8d9a6158a069930370f5d63a5afbce2d..5534dd45050b4bc9447f05bdc8bc2ab287a97d30 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
@@ -56,9 +56,9 @@ import java.util.stream.Stream;
 
 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.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;
@@ -80,7 +80,7 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 // Much of this code was influences/transcribed from GnuR src/main/platform.c
 
@@ -92,8 +92,8 @@ public class FileFunctions {
         private static final int WRITE = 2;
         private static final int READ = 4;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileAccess.class);
             casts.arg("names").mustBe(stringValue()).asStringVector();
             casts.arg("mode").asIntegerVector().findFirst().mustBe(gte(0).and(lte(7)));
         }
@@ -124,8 +124,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "file.append", kind = INTERNAL, parameterNames = {"file1", "file2"}, behavior = IO)
     public abstract static class FileAppend extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileAppend.class);
             casts.arg("file1").mustBe(stringValue()).asStringVector();
             casts.arg("file2").mustBe(stringValue()).asStringVector();
         }
@@ -219,8 +220,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "file.create", kind = INTERNAL, parameterNames = {"vec", "showWarnings"}, behavior = IO)
     public abstract static class FileCreate extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileCreate.class);
             casts.arg("vec").mustBe(stringValue()).asStringVector();
             casts.arg("showWarnings").asLogicalVector().findFirst().mapIf(logicalNA(), constant(RRuntime.LOGICAL_FALSE));
         }
@@ -265,8 +267,8 @@ public class FileFunctions {
 
         @Child private SetClassAttributeNode setClassAttrNode;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileInfo.class);
             casts.arg("extra_cols").asLogicalVector().findFirst().map(toBoolean());
         }
 
@@ -422,8 +424,9 @@ public class FileFunctions {
     }
 
     private abstract static class FileLinkAdaptor extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileLinkAdaptor.class);
             casts.arg("from").mustBe(stringValue(), RError.Message.INVALID_FIRST_FILENAME).asStringVector();
             casts.arg("to").mustBe(stringValue(), RError.Message.INVALID_SECOND_FILENAME).asStringVector();
         }
@@ -486,8 +489,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.remove", kind = INTERNAL, parameterNames = {"file"}, behavior = IO)
     public abstract static class FileRemove extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileRemove.class);
             casts.arg("file").mustBe(stringValue(), RError.Message.INVALID_FIRST_FILENAME).asStringVector();
         }
 
@@ -514,8 +517,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "file.rename", kind = INTERNAL, parameterNames = {"from", "to"}, behavior = IO)
     public abstract static class FileRename extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(FileRename.class);
             casts.arg("from").mustBe(stringValue()).asStringVector();
             casts.arg("to").mustBe(stringValue()).asStringVector();
         }
@@ -550,8 +554,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.exists", kind = INTERNAL, parameterNames = {"file"}, behavior = IO)
     public abstract static class FileExists extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileExists.class);
             casts.arg("file").mustBe(stringValue()).asStringVector();
         }
 
@@ -579,8 +583,8 @@ public class FileFunctions {
         private static final String DOT = ".";
         private static final String DOTDOT = "..";
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ListFiles.class);
             casts.arg("path").mustBe(stringValue()).asStringVector();
             casts.arg("pattern").allowNull().mustBe(stringValue());
             casts.arg("all.files").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -720,8 +724,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "list.dirs", kind = INTERNAL, parameterNames = {"directory", "full.names", "recursive"}, behavior = IO)
     public abstract static class ListDirs extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ListDirs.class);
             casts.arg("directory").mustBe(stringValue()).asStringVector();
             casts.arg("full.names").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("recursive").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -776,8 +781,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.path", kind = INTERNAL, parameterNames = {"paths", "fsep"}, behavior = IO)
     public abstract static class FilePath extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FilePath.class);
             casts.arg("paths").mustBe(instanceOf(RList.class), RError.Message.INVALID_FIRST_ARGUMENT);
             casts.arg("fsep").mustBe(stringValue()).asStringVector().findFirst().notNA();
         }
@@ -875,8 +880,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.copy", kind = INTERNAL, parameterNames = {"from", "to", "overwrite", "recursive", "copy.mode", "copy.date"}, behavior = IO)
     public abstract static class FileCopy extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileCopy.class);
             casts.arg("from").mustBe(stringValue()).asStringVector();
             casts.arg("to").mustBe(stringValue()).asStringVector();
             casts.arg("overwrite").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -1010,8 +1015,8 @@ public class FileFunctions {
     @RBuiltin(name = "file.show", kind = INTERNAL, parameterNames = {"files", "header", "title", "delete.file", "pager"}, visibility = OFF, behavior = IO)
     public abstract static class FileShow extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(FileShow.class);
             casts.arg("files").asStringVector();
             casts.arg("header").asStringVector();
             casts.arg("title").asStringVector();
@@ -1067,8 +1072,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "dirname", kind = INTERNAL, parameterNames = {"path"}, behavior = IO)
     public abstract static class DirName extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DirName.class);
             casts.arg("path").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
         }
 
@@ -1086,8 +1092,8 @@ public class FileFunctions {
     @RBuiltin(name = "basename", kind = INTERNAL, parameterNames = {"path"}, behavior = IO)
     public abstract static class BaseName extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(BaseName.class);
             casts.arg("path").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
         }
 
@@ -1105,8 +1111,8 @@ public class FileFunctions {
     @RBuiltin(name = "unlink", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "recursive", "force"}, behavior = IO)
     public abstract static class Unlink extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Unlink.class);
             casts.arg("x").mustBe(stringValue(), RError.Message.CHAR_VEC_ARGUMENT);
             casts.arg("recursive").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("force").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -1174,8 +1180,8 @@ public class FileFunctions {
     @RBuiltin(name = "dir.create", visibility = OFF, kind = INTERNAL, parameterNames = {"path", "showWarnings", "recursive", "mode"}, behavior = IO)
     public abstract static class DirCreate extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(DirCreate.class);
             casts.arg("path").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
             casts.arg("showWarnings").asLogicalVector().findFirst().map(toBoolean());
             casts.arg("recursive").asLogicalVector().findFirst().map(toBoolean());
@@ -1184,7 +1190,8 @@ public class FileFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected byte dirCreate(String pathIn, boolean showWarnings, boolean recursive, int octMode) {
+        protected byte dirCreate(String pathIn, boolean showWarnings, boolean recursive, int octMode,
+                        @Cached("create()") BaseRFFI.MkdirNode mkdirNode) {
             boolean ok;
             if (RRuntime.isNA(pathIn)) {
                 ok = false;
@@ -1192,32 +1199,32 @@ public class FileFunctions {
                 ok = true;
                 String path = Utils.tildeExpand(pathIn);
                 if (recursive) {
-                    ok = mkparentdirs(new File(path).getAbsoluteFile().getParentFile(), showWarnings, octMode);
+                    ok = mkparentdirs(mkdirNode, new File(path).getAbsoluteFile().getParentFile(), showWarnings, octMode);
                 }
                 if (ok) {
-                    ok = mkdir(path, showWarnings, octMode);
+                    ok = mkdir(mkdirNode, path, showWarnings, octMode);
                 }
             }
             return RRuntime.asLogical(ok);
         }
 
-        private boolean mkparentdirs(File file, boolean showWarnings, int mode) {
+        private boolean mkparentdirs(BaseRFFI.MkdirNode mkdirNode, File file, boolean showWarnings, int mode) {
             if (file.isDirectory()) {
                 return true;
             }
             if (file.exists()) {
                 return false;
             }
-            if (mkparentdirs(file.getParentFile(), showWarnings, mode)) {
-                return mkdir(file.getAbsolutePath(), showWarnings, mode);
+            if (mkparentdirs(mkdirNode, file.getParentFile(), showWarnings, mode)) {
+                return mkdir(mkdirNode, file.getAbsolutePath(), showWarnings, mode);
             } else {
                 return false;
             }
         }
 
-        private boolean mkdir(String path, boolean showWarnings, int mode) {
+        private boolean mkdir(BaseRFFI.MkdirNode mkdirNode, String path, boolean showWarnings, int mode) {
             try {
-                RFFIFactory.getRFFI().getBaseRFFI().mkdir(path, mode);
+                mkdirNode.execute(path, mode);
                 return true;
             } catch (IOException ex) {
                 if (showWarnings) {
@@ -1230,8 +1237,9 @@ public class FileFunctions {
 
     @RBuiltin(name = "dir.exists", kind = INTERNAL, parameterNames = "paths", behavior = IO)
     public abstract static class DirExists extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(DirExists.class);
             casts.arg("paths").mustBe(stringValue()).asStringVector();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java
index 39e733fef1823dde286cd2a08816303df636c05e..605e55f3fb557cbafdb69fdae364aea1b56d8296 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Floor.java
@@ -29,7 +29,6 @@ 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.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RType;
@@ -47,16 +46,10 @@ public abstract class Floor extends UnaryArithmeticBuiltinNode {
         super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).
-            mustBe(numericValue()).
-            asDoubleVector(true, true, true);
-        //@formatter:on
+    static {
+        Casts casts = new Casts(Floor.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustNotBeNull().mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector(true,
+                        true, true);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java
index 6c887d5b429a4b99aa93b88879760ea4404a9e99..3368086a659ce6075b865ceb209bfabdbddb19b2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForceAndCall.java
@@ -29,15 +29,11 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 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.frame.FrameSlot;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
-import com.oracle.truffle.r.nodes.access.FrameSlotNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
-import com.oracle.truffle.r.nodes.function.RCallBaseNode;
-import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -47,15 +43,12 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 @RBuiltin(name = "forceAndCall", kind = PRIMITIVE, parameterNames = {"n", "FUN", "..."}, nonEvalArgs = 2, behavior = COMPLEX)
 public abstract class ForceAndCall extends RBuiltinNode {
 
-    private final Object argsIdentifier = new Object();
-
-    @Child private RCallBaseNode call = RCallNode.createExplicitCall(argsIdentifier);
-    @Child private FrameSlotNode slot = FrameSlotNode.createTemp(argsIdentifier, true);
+    @Child private RExplicitCallNode call = RExplicitCallNode.create();
 
     @Child private PromiseHelperNode promiseHelper;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ForceAndCall.class);
         casts.arg("n").asIntegerVector().findFirst();
         // TODO other types are possible for FUN that we don't yet handle
         casts.arg("FUN").mustBe(instanceOf(RFunction.class), RError.Message.INVALID_OR_UNIMPLEMENTED_ARGUMENTS);
@@ -67,14 +60,7 @@ public abstract class ForceAndCall extends RBuiltinNode {
         if (!fun.isBuiltin()) {
             flattenFirstArgs(frame, cachedN, args);
         }
-
-        FrameSlot frameSlot = slot.executeFrameSlot(frame);
-        try {
-            frame.setObject(frameSlot, args);
-            return call.execute(frame, fun);
-        } finally {
-            frame.setObject(frameSlot, null);
-        }
+        return call.execute(frame, fun, args);
     }
 
     @ExplodeLoop
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java
index bf66ca987b5084ad4646e9f6be7c9696d80d838c..ce083781b25870a75ff9adef33030549d86bac59 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Formals.java
@@ -43,6 +43,10 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 @RBuiltin(name = "formals", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
 public abstract class Formals extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Formals.class);
+    }
+
     @SuppressWarnings("unused")
     @Specialization(limit = "3", guards = "fun == cachedFunction")
     protected Object formalsCached(RFunction fun,
@@ -51,7 +55,7 @@ public abstract class Formals extends RBuiltinNode {
         return formals;
     }
 
-    @Specialization(contains = "formalsCached")
+    @Specialization(replaces = "formalsCached")
     protected Object formals(RFunction fun) {
         return createFormals(fun);
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
index 5c9e5594e3badf9d2621198dcece5729469fb97e..ad0e3d20d3e60291bb8f9203c6e36f8d414f8a3a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -20,7 +20,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -31,6 +30,7 @@ import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen;
 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.RLogical;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
@@ -39,6 +39,7 @@ 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.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @SuppressWarnings("unused")
 @RBuiltin(name = "format", kind = INTERNAL, parameterNames = {"x", "trim", "digits", "nsmall", "width", "justify", "na.encode", "scientific", "decimal.mark"}, behavior = PURE)
@@ -86,8 +87,8 @@ public abstract class Format extends RBuiltinNode {
         return (RAbstractIntVector) castInteger.execute(operand);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Format.class);
         casts.arg("x");
         casts.arg("trim").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).notNA().map(toBoolean());
         casts.arg("digits").asIntegerVector().findFirst(RRuntime.INT_NA).mustBe(intNA().or(gte(R_MIN_DIGITS_OPT).and(lte(R_MAX_DIGITS_OPT))));
@@ -100,15 +101,15 @@ public abstract class Format extends RBuiltinNode {
     }
 
     @Specialization
-    protected RStringVector format(VirtualFrame frame, RAbstractLogicalVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
+    protected RStringVector format(RAbstractLogicalVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
                     String decimalMark) {
-        return (RStringVector) valuePrinter.prettyPrint(frame, value, AnyVectorToStringVectorWriter::new);
+        return (RStringVector) valuePrinter.prettyPrint(value, AnyVectorToStringVectorWriter::new);
     }
 
     @Specialization
-    protected RStringVector format(VirtualFrame frame, RAbstractIntVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
+    protected RStringVector format(RAbstractIntVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
                     String decimalMark) {
-        return (RStringVector) valuePrinter.prettyPrint(frame, value, AnyVectorToStringVectorWriter::new);
+        return (RStringVector) valuePrinter.prettyPrint(value, AnyVectorToStringVectorWriter::new);
     }
 
     // TODO: even though format's arguments are not used at this point, their processing mirrors
@@ -134,15 +135,21 @@ public abstract class Format extends RBuiltinNode {
     }
 
     @Specialization
-    protected RStringVector format(VirtualFrame frame, RAbstractDoubleVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
+    protected RStringVector format(RAbstractDoubleVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
                     String decimalMark) {
-        return (RStringVector) valuePrinter.prettyPrint(frame, value, AnyVectorToStringVectorWriter::new);
+        return (RStringVector) valuePrinter.prettyPrint(value, AnyVectorToStringVectorWriter::new);
     }
 
     @Specialization
-    protected RStringVector format(VirtualFrame frame, RAbstractComplexVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
+    protected RStringVector format(RAbstractComplexVector value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
                     String decimalMark) {
-        return (RStringVector) valuePrinter.prettyPrint(frame, value, AnyVectorToStringVectorWriter::new);
+        return (RStringVector) valuePrinter.prettyPrint(value, AnyVectorToStringVectorWriter::new);
+    }
+
+    @Specialization
+    protected RStringVector format(REnvironment value, boolean trim, int digits, int nsmall, int width, int justify, boolean naEncode, int scientific,
+                    String decimalMark) {
+        return RDataFactory.createStringVector(value.getPrintName());
     }
 
     @Specialization
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 c69f2dac6af092d2932465d0d8d60fb9974cf2ee..b872f1187f29cf756fad56b82a38f542b7b99f37 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
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -18,7 +18,6 @@ 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;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
@@ -40,8 +39,8 @@ public abstract class FormatC extends RBuiltinNode {
         return (RStringVector) ((RStringVector) castStringNode.executeString(o)).copyDropAttributes();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FormatC.class);
         casts.arg("x");
         casts.arg("mode").asStringVector().findFirst();
         casts.arg("width").asIntegerVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
index 1414d6169950dbcc6fcf4148756d5b2b9f01a609..109ff35ab3afc3574385174926eee5f95bf7ab74 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java
@@ -45,7 +45,6 @@ import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.FrameFunctionsFactory.SysFrameNodeGen;
 import com.oracle.truffle.r.nodes.function.ArgumentMatcher;
@@ -187,8 +186,8 @@ public class FrameFunctions {
     @RBuiltin(name = "sys.call", kind = INTERNAL, parameterNames = {"which"}, behavior = COMPLEX)
     public abstract static class SysCall extends FrameHelper {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysCall.class);
             casts.arg("which").asIntegerVector().findFirst();
         }
 
@@ -238,8 +237,8 @@ public class FrameFunctions {
             return FrameAccess.READ_ONLY;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(MatchCall.class);
             casts.arg("definition").mustBe(RFunction.class);
             casts.arg("call").mustBe(RLanguage.class);
             casts.arg("expand.dots").asLogicalVector().findFirst();
@@ -447,8 +446,8 @@ public class FrameFunctions {
             return FrameAccess.MATERIALIZE;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysFrame.class);
             casts.arg("which").asIntegerVector().findFirst();
         }
 
@@ -555,8 +554,8 @@ public class FrameFunctions {
         private final BranchProfile promiseProfile = BranchProfile.create();
         private final BranchProfile nonNullCallerProfile = BranchProfile.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysParent.class);
             casts.arg("n").asIntegerVector().findFirst();
         }
 
@@ -589,8 +588,8 @@ public class FrameFunctions {
             return FrameAccess.READ_ONLY;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysFunction.class);
             casts.arg("which").asIntegerVector().findFirst();
         }
 
@@ -661,8 +660,8 @@ public class FrameFunctions {
 
         public abstract REnvironment execute(VirtualFrame frame, int n);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ParentFrame.class);
             casts.arg("n").asIntegerVector().findFirst();
         }
 
@@ -682,7 +681,7 @@ public class FrameFunctions {
             return REnvironment.frameToEnvironment(getCaller.execute(frame));
         }
 
-        @Specialization(contains = "parentFrameDirect")
+        @Specialization(replaces = "parentFrameDirect")
         protected REnvironment parentFrame(VirtualFrame frame, int n) {
             if (n <= 0) {
                 errorProfile.enter();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
index 4f5573978e11e9fcb57bc9e72ca495c8d375f30d..ad8d21132c6fc067f75dc68ed45e317711fd6812 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Gc.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector;
 @RBuiltin(name = "gc", kind = INTERNAL, parameterNames = {"verbose", "reset"}, behavior = COMPLEX)
 public abstract class Gc extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Gc.class);
         casts.arg("verbose").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("reset").asLogicalVector().findFirst().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
index cc9cc4610d5b5904b84b2414e6b8555aee3ca8e1..2a2ddedc86d4c3646e9a1e66ae271b6ab961dc78 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetClass.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -25,6 +25,10 @@ public abstract class GetClass extends RBuiltinNode {
 
     @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(true, false);
 
+    static {
+        Casts.noCasts(GetClass.class);
+    }
+
     @Specialization
     protected RAbstractStringVector getClass(Object x) {
         return classHierarchy.execute(x);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
index 5e425c311184a247df5571b212574eb7980f1cc3..cae0c2dcee59304515f6848f2c2bed44e1aadd12 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,6 @@ import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
@@ -168,13 +167,13 @@ public class GetFunctions {
 
         public abstract Object execute(VirtualFrame frame, String x, REnvironment environment, String mode, boolean inherits);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Get.class);
             casts.arg("x").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("envir").mustBe(instanceOf(REnvironment.class).or(integerValue()).or(doubleValue()).or(instanceOf(RS4Object.class))).mapIf(integerValue().or(doubleValue()),
                             chain(asIntegerVector()).with(findFirst().integerElement()).end());
             casts.arg("mode").mustBe(stringValue()).asStringVector().findFirst();
-            casts.arg("inherits").allowNull().asLogicalVector().findFirst().map(toBoolean());
+            casts.arg("inherits").asLogicalVector().findFirst().map(toBoolean());
         }
 
         @Specialization
@@ -205,13 +204,13 @@ public class GetFunctions {
 
         private final ConditionProfile inheritsProfile = ConditionProfile.createBinaryProfile();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Get0.class);
             casts.arg("x").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("envir").mustBe(instanceOf(REnvironment.class).or(integerValue()).or(doubleValue()).or(instanceOf(RS4Object.class))).mapIf(integerValue().or(doubleValue()),
                             chain(asIntegerVector()).with(findFirst().integerElement()).end());
             casts.arg("mode").mustBe(stringValue()).asStringVector().findFirst();
-            casts.arg("inherits").allowNull().asLogicalVector().findFirst().map(toBoolean());
+            casts.arg("inherits").asLogicalVector().findFirst().map(toBoolean());
         }
 
         @Specialization
@@ -252,8 +251,8 @@ public class GetFunctions {
 
         @CompilationFinal private boolean needsCallerFrame;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(MGet.class);
             casts.arg("x").mustBe(stringValue()).asStringVector();
             casts.arg("envir").mustBe(instanceOf(REnvironment.class).or(integerValue()).or(doubleValue()).or(instanceOf(RS4Object.class))).mapIf(integerValue().or(doubleValue()),
                             chain(asIntegerVector()).with(findFirst().integerElement()).end());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java
index 26ce406f1cf720e2da49ce66c5a1b3db8d5ff58d..374a9e866f1f6a004bdfea7e950ce74fc0a9d4ca 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetOldClass.java
@@ -40,6 +40,10 @@ public abstract class GetOldClass extends RBuiltinNode {
     private final ConditionProfile isObjectProfile = ConditionProfile.createBinaryProfile();
     @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create();
 
+    static {
+        Casts.noCasts(GetOldClass.class);
+    }
+
     @Specialization
     protected Object getOldClass(RAbstractContainer arg) {
         if (isObjectProfile.profile(getClassNode.isObject(arg))) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java
index be2ae78d8794067dda33480979066cf13f8a8322..32583e1a76f101e2d4245db0411b2c3e814297df 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetText.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -35,10 +34,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "gettext", kind = INTERNAL, parameterNames = {"domain", "args"}, behavior = PURE)
 public abstract class GetText extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(GetText.class);
         casts.arg("domain").asStringVector().findFirst("");
-        casts.arg("args").allowNull().asStringVector();
+        casts.arg("args").asStringVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Getwd.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Getwd.java
index d0833557089e978f985b61f9d8a5eab136c11894..1e5ab0b3745b9f0e3134bd0d4c8857ab05fc4cc7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Getwd.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Getwd.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,15 +30,17 @@ 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.RDataFactory;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 @RBuiltin(name = "getwd", kind = INTERNAL, parameterNames = {}, behavior = IO)
 public abstract class Getwd extends RBuiltinNode {
 
+    @Child private BaseRFFI.GetwdNode getwdNode = BaseRFFI.GetwdNode.create();
+
     @Specialization
     @TruffleBoundary
     protected Object getwd() {
-        String result = RFFIFactory.getRFFI().getBaseRFFI().getwd();
+        String result = getwdNode.execute();
         return RDataFactory.createStringVector(result);
     }
 }
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 762279f9518609c0750dd83411679b2fc07e79a3..2f45bf6836886d361715191b1a1da808950653a1 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
@@ -28,7 +28,6 @@ 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;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -64,47 +63,48 @@ 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();
+        @Child protected PCRERFFI.MaketablesNode maketablesNode = RFFIFactory.getRFFI().getPCRERFFI().createMaketablesNode();
+        @Child protected PCRERFFI.CompileNode compileNode = RFFIFactory.getRFFI().getPCRERFFI().createCompileNode();
 
-        protected void castPattern(CastBuilder casts) {
+        protected static void castPattern(Casts casts) {
             // with default error message, NO_CALLER does not work
             casts.arg("pattern").mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "pattern").asVector().mustBe(notEmpty(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT,
                             "pattern");
         }
 
-        protected void castText(CastBuilder casts, String textId) {
+        protected static void castText(Casts casts, String textId) {
             casts.arg(textId).mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, textId);
         }
 
-        protected void castIgnoreCase(CastBuilder casts) {
+        protected static void castIgnoreCase(Casts casts) {
             casts.arg("ignore.case").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castPerl(CastBuilder casts) {
+        protected static void castPerl(Casts casts) {
             casts.arg("perl").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castFixed(CastBuilder casts, byte defaultValue) {
+        protected static void castFixed(Casts casts, byte defaultValue) {
             casts.arg("fixed").asLogicalVector().findFirst(defaultValue);
         }
 
-        protected void castValue(CastBuilder casts) {
+        protected static void castValue(Casts casts) {
             casts.arg("value").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castUseBytes(CastBuilder casts) {
+        protected static void castUseBytes(Casts casts) {
             casts.arg("useBytes").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castInvert(CastBuilder casts) {
+        protected static void castInvert(Casts casts) {
             casts.arg("invert").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected void castCosts(CastBuilder casts) {
+        protected static void castCosts(Casts casts) {
             casts.arg("costs").asIntegerVector();
         }
 
-        protected void castBounds(CastBuilder casts) {
+        protected static void castBounds(Casts casts) {
             casts.arg("bounds").asDoubleVector();
         }
 
@@ -202,8 +202,8 @@ public class GrepFunctions {
 
         protected PCRERFFI.Result compilePerlPattern(String pattern, boolean ignoreCase) {
             int cflags = ignoreCase ? PCRERFFI.CASELESS : 0;
-            long tables = pcreRFFINode.maketables();
-            PCRERFFI.Result pcre = pcreRFFINode.compile(pattern, cflags, tables);
+            long tables = maketablesNode.execute();
+            PCRERFFI.Result pcre = compileNode.execute(pattern, cflags, tables);
             if (pcre.result == 0) {
                 // TODO output warning if pcre.errorMessage not NULL
                 throw RError.error(this, RError.Message.INVALID_REGEXP, pattern);
@@ -213,6 +213,8 @@ public class GrepFunctions {
     }
 
     private abstract static class GrepAdapter extends CommonCodeAdapter {
+        @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
+
         protected Object doGrep(RAbstractStringVector patternArgVec, RAbstractStringVector vector, byte ignoreCaseLogical, byte valueLogical, byte perlLogical, byte fixedLogical,
                         @SuppressWarnings("unused") byte useBytes, byte invertLogical, boolean grepl) {
             boolean value = RRuntime.fromLogical(valueLogical);
@@ -242,7 +244,7 @@ public class GrepFunctions {
                 for (int i = 0; i < len; i++) {
                     String text = vector.getDataAt(i);
                     if (!RRuntime.isNA(text)) {
-                        if (pcreRFFINode.exec(pcre.result, 0, text, 0, 0, ovector) >= 0) {
+                        if (execNode.execute(pcre.result, 0, text, 0, 0, ovector) >= 0) {
                             matches[i] = true;
                         }
                     }
@@ -319,8 +321,8 @@ public class GrepFunctions {
     @RBuiltin(name = "grep", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "value", "perl", "fixed", "useBytes", "invert"}, behavior = PURE)
     public abstract static class Grep extends GrepAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Grep.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -342,8 +344,8 @@ public class GrepFunctions {
     @RBuiltin(name = "grepl", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "value", "perl", "fixed", "useBytes", "invert"}, behavior = PURE)
     public abstract static class GrepL extends GrepAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GrepL.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -364,8 +366,9 @@ public class GrepFunctions {
     }
 
     protected abstract static class SubAdapter extends CommonCodeAdapter {
+        @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
 
-        protected void castReplacement(CastBuilder casts) {
+        protected static void castReplacement(Casts casts) {
             // with default error message, NO_CALLER does not work
             casts.arg("replacement").mustBe(stringValue(), RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "replacement").asVector().mustBe(notEmpty(), RError.NO_CALLER,
                             RError.Message.INVALID_ARGUMENT, "replacement");
@@ -433,7 +436,7 @@ public class GrepFunctions {
                                                                            // necessary
 
                         StringBuffer sb = new StringBuffer();
-                        while (pcreRFFINode.exec(pcre.result, 0, input, lastEndOffset, eflag, ovector) >= 0) {
+                        while (execNode.execute(pcre.result, 0, input, lastEndOffset, eflag, ovector) >= 0) {
                             nmatch++;
 
                             // offset == byte position
@@ -641,8 +644,8 @@ public class GrepFunctions {
     @RBuiltin(name = "sub", kind = INTERNAL, parameterNames = {"pattern", "replacement", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class Sub extends SubAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sub.class);
             castPattern(casts);
             castReplacement(casts);
             castText(casts, "text");
@@ -663,8 +666,8 @@ public class GrepFunctions {
     @RBuiltin(name = "gsub", kind = INTERNAL, parameterNames = {"pattern", "replacement", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class GSub extends SubAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GSub.class);
             castPattern(casts);
             castReplacement(casts);
             castText(casts, "text");
@@ -691,9 +694,12 @@ public class GrepFunctions {
         @Child SetFixedAttributeNode setCaptureLengthAttrNode = SetFixedAttributeNode.create("capture.length");
         @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
         @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
+        @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
+        @Child PCRERFFI.GetCaptureNamesNode getCaptureNamesNode = RFFIFactory.getRFFI().getPCRERFFI().createGetCaptureNamesNode();
+        @Child PCRERFFI.GetCaptureCountNode getCaptureCountNode = RFFIFactory.getRFFI().getPCRERFFI().createGetCaptureCountNode();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Regexp.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -818,13 +824,13 @@ public class GrepFunctions {
                 }
             } else if (perl) {
                 PCRERFFI.Result pcre = compilePerlPattern(pattern, ignoreCase);
-                int maxCaptureCount = pcreRFFINode.getCaptureCount(pcre.result, 0);
+                int maxCaptureCount = getCaptureCountNode.execute(pcre.result, 0);
                 int[] ovector = new int[(maxCaptureCount + 1) * 3];
                 int offset = 0;
                 while (true) {
-                    int captureCount = pcreRFFINode.exec(pcre.result, 0, text, offset, 0, ovector);
+                    int captureCount = execNode.execute(pcre.result, 0, text, offset, 0, ovector);
                     if (captureCount >= 0) {
-                        String[] captureNames = pcreRFFINode.getCaptureNames(pcre.result, 0, maxCaptureCount);
+                        String[] captureNames = getCaptureNamesNode.execute(pcre.result, 0, maxCaptureCount);
                         for (int i = 0; i < captureNames.length; i++) {
                             if (captureNames[i] == null) {
                                 captureNames[i] = "";
@@ -880,8 +886,8 @@ public class GrepFunctions {
         @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
         @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Gregexpr.class);
             castPattern(casts);
             castText(casts, "text");
             castIgnoreCase(casts);
@@ -1019,8 +1025,8 @@ public class GrepFunctions {
     @RBuiltin(name = "agrep", kind = INTERNAL, parameterNames = {"pattern", "x", "ignore.case", "value", "costs", "bounds", "useBytes", "fixed"}, behavior = PURE)
     public abstract static class AGrep extends CommonCodeAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AGrep.class);
             castPattern(casts);
             castText(casts, "x");
             castIgnoreCase(casts);
@@ -1135,8 +1141,8 @@ public class GrepFunctions {
     @RBuiltin(name = "agrepl", kind = INTERNAL, parameterNames = {"pattern", "x", "ignore.case", "value", "costs", "bounds", "useBytes", "fixed"}, behavior = PURE)
     public abstract static class AGrepL extends CommonCodeAdapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(AGrepL.class);
             castPattern(casts);
             castText(casts, "x");
             castIgnoreCase(casts);
@@ -1165,9 +1171,10 @@ public class GrepFunctions {
 
     @RBuiltin(name = "strsplit", kind = INTERNAL, parameterNames = {"x", "split", "fixed", "perl", "useBytes"}, behavior = PURE)
     public abstract static class Strsplit extends CommonCodeAdapter {
+        @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Strsplit.class);
             casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER);
             casts.arg("split").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER);
             castFixed(casts, RRuntime.LOGICAL_FALSE);
@@ -1186,7 +1193,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 ? pcreRFFINode.maketables() : 0;
+            long pcreTables = perl ? maketablesNode.execute() : 0;
             PCRERFFI.Result[] pcreSplits = perl ? new PCRERFFI.Result[splits.length] : null;
 
             na.enable(x);
@@ -1195,7 +1202,7 @@ public class GrepFunctions {
                 splits[i] = fixed || perl ? split.getDataAt(i) : RegExp.checkPreDefinedClasses(split.getDataAt(i));
                 if (perl) {
                     if (!currentSplit.isEmpty()) {
-                        pcreSplits[i] = pcreRFFINode.compile(currentSplit, 0, pcreTables);
+                        pcreSplits[i] = compileNode.execute(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);
@@ -1299,7 +1306,7 @@ public class GrepFunctions {
             int[] ovector = new int[30];
             int[] fromByteMapping = getFromByteMapping(data); // non-null if it's necessary
 
-            while (pcreRFFINode.exec(pcre.result, 0, data, lastEndOffset, 0, ovector) >= 0) {
+            while (execNode.execute(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 c30b36ab7e5ad1f285953e338957c3fa5f2c1f79..6d4a9370e312e67de7d2ab785a536ca5b552db71 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
@@ -37,7 +37,6 @@ 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;
 import com.oracle.truffle.r.nodes.function.RCallNode;
@@ -90,8 +89,8 @@ public class HiddenInternalFunctions {
             }
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(MakeLazy.class);
             casts.arg("names").mustBe(stringValue()).asStringVector();
             casts.arg("eval.env").mustBe(instanceOf(REnvironment.class));
             casts.arg("assign.env").mustBe(instanceOf(REnvironment.class));
@@ -144,8 +143,9 @@ public class HiddenInternalFunctions {
      */
     @RBuiltin(name = "importIntoEnv", kind = INTERNAL, parameterNames = {"impenv", "impnames", "expenv", "expnames"}, behavior = COMPLEX)
     public abstract static class ImportIntoEnv extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ImportIntoEnv.class);
             casts.arg("impenv").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class), RError.Message.BAD_ENVIRONMENT, "import");
             casts.arg("impnames").defaultError(RError.Message.INVALID_ARGUMENT, "names").mustBe(stringValue()).asStringVector();
             casts.arg("expenv").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class), RError.Message.BAD_ENVIRONMENT, "import");
@@ -188,8 +188,8 @@ public class HiddenInternalFunctions {
 
         @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LazyLoadDBFetch.class);
             casts.arg("compressed").asIntegerVector().findFirst();
         }
 
@@ -278,6 +278,10 @@ public class HiddenInternalFunctions {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{".C", ".Call", ".Fortran", ".External"}, RDataFactory.COMPLETE_VECTOR);
         private static final RStringVector NATIVE_ROUTINE_LIST = RDataFactory.createStringVectorFromScalar("NativeRoutineList");
 
+        static {
+            Casts.noCasts(GetRegisteredRoutines.class);
+        }
+
         @Specialization
         protected RList getRegisteredRoutines(@SuppressWarnings("unused") RNull info) {
             throw RError.error(this, RError.Message.NULL_DLLINFO);
@@ -323,6 +327,10 @@ public class HiddenInternalFunctions {
     public abstract static class GetVarsFromFrame extends RBuiltinNode {
         @Child private PromiseHelperNode promiseHelper;
 
+        static {
+            Casts.noCasts(GetVarsFromFrame.class);
+        }
+
         @Specialization
         protected RList getVarsFromFrame(VirtualFrame frame, RAbstractStringVector varsVec, REnvironment env, byte forceArg) {
             boolean force = RRuntime.fromLogical(forceArg);
@@ -357,8 +365,8 @@ public class HiddenInternalFunctions {
 
         @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LazyLoadDBinsertValue.class);
             casts.arg("ascii").asIntegerVector().findFirst();
             casts.arg("compsxp").asIntegerVector().findFirst();
         }
@@ -458,6 +466,11 @@ public class HiddenInternalFunctions {
 
     @RBuiltin(name = "lazyLoadDBflush", kind = INTERNAL, parameterNames = "path", behavior = COMPLEX)
     public abstract static class LazyLoadDBFlush extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(LazyLoadDBFlush.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull doLazyLoadDBFlush(RAbstractStringVector dbPath) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java
index a470aa85cc64194336ccdb247259e3249e9b3f94..62b894730ecde4abf897289b4e4561d5e0e1be86 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IConv.java
@@ -28,7 +28,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "iconv", kind = INTERNAL, parameterNames = {"x", "from", "to", "sub", "mark", "toRaw"}, behavior = PURE)
 public abstract class IConv extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IConv.class);
         casts.arg("x").mustBe(stringValue(), RError.NO_CALLER, RError.Message.NOT_CHARACTER_VECTOR, "x");
         // with default error message, NO_CALLER does not work
         casts.arg("from").defaultError(RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "from").mustBe(stringValue()).asStringVector().mustBe(size(1));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
index f1a329fcac628d268a1adc5fe061ed14f7e8df4c..3f5769de6059e2d3da274be8e43051401d5a7aa1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ 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.IterableAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -77,8 +76,8 @@ public abstract class Identical extends RBuiltinNode {
     @Child private IterableAttributeNode attrIterNodeX = IterableAttributeNode.create();
     @Child private IterableAttributeNode attrIterNodeY = IterableAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Identical.class);
         casts.arg("num.eq").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         casts.arg("single.NA").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         casts.arg("attrib.as.set").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java
index d4c874044f992a6f1cd85801353fb18491f6cab5..b45abeda284522f6bda8d51103d0b086b674529f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/InheritsBuiltin.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -20,7 +20,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.InheritsNode;
 import com.oracle.truffle.r.nodes.unary.InheritsNodeGen;
@@ -34,8 +33,8 @@ public abstract class InheritsBuiltin extends RBuiltinNode {
 
     public abstract Object execute(Object x, Object what, Object which);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(InheritsBuiltin.class);
         casts.arg("what").mustBe(stringValue(), NOT_CHARACTER_VECTOR, "what");
         casts.arg("which").mustBe(logicalValue(), NOT_LEN_ONE_LOGICAL_VECTOR, "which").asLogicalVector().findFirst().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java
index 9b65d700b6a7e99b15d7b2ac17a87b9af8f28c56..0b85315703321a178abb85d2a20782ad5fb1d173 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToBits.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -37,9 +36,9 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 @RBuiltin(name = "intToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class IntToBits extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asIntegerVector();
+    static {
+        Casts casts = new Casts(IntToBits.class);
+        casts.arg("x").asIntegerVector();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java
index 701d18fb0ddb15d9b19b868a399503934125b904..51a84c924e9abfcbc60145876e037daae5afa825 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IntToUtf8.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 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.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;
@@ -44,9 +43,9 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 @RBuiltin(name = "intToUtf8", kind = INTERNAL, parameterNames = {"x", "multiple"}, behavior = PURE)
 public abstract class IntToUtf8 extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asIntegerVector();
+    static {
+        Casts casts = new Casts(IntToUtf8.class);
+        casts.arg("x").asIntegerVector();
         casts.arg("multiple").mustNotBeNull().asLogicalVector().findFirst().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java
index c30e2666760295444d105e320e58ff5963cf58b0..55ec16e7d4e238195b4c80da059c9f524a5b9525 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Invisible.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "invisible", visibility = OFF, kind = PRIMITIVE, parameterNames = {"x"}, behavior = COMPLEX)
 public abstract class Invisible extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Invisible.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RNull.instance};
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsATTY.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsATTY.java
index 92198306f2147525fa9cb044ecd8b4afad4a675f..32fe9994366140e09659f5fd7309885739dc5d9b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsATTY.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsATTY.java
@@ -40,6 +40,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "isatty", kind = INTERNAL, parameterNames = {"con"}, behavior = PURE)
 public abstract class IsATTY extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(IsATTY.class);
+    }
+
     @Specialization
     @TruffleBoundary
     protected byte isATTYNonConnection(RAbstractIntVector con) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java
index 32634f340058a8195c16d16ee6dea96c987d8017..f1ce895c28b731c223a6d7aff58f444a03e86ec9 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -132,6 +132,10 @@ public class IsFiniteFunctions {
     @RBuiltin(name = "is.finite", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsFinite extends Adapter {
 
+        static {
+            Casts.noCasts(IsFinite.class);
+        }
+
         @Specialization
         protected RLogicalVector doIsFinite(RAbstractDoubleVector vec) {
             return doFunDouble(vec, RRuntime::isFinite);
@@ -142,7 +146,7 @@ public class IsFiniteFunctions {
             return doFunConstant(vec, RRuntime.LOGICAL_TRUE);
         }
 
-        @Specialization(contains = "doComplete")
+        @Specialization(replaces = "doComplete")
         protected RLogicalVector doIsFinite(RAbstractIntVector vec) {
             return doFunInt(vec, value -> !RRuntime.isNA(value));
         }
@@ -152,7 +156,7 @@ public class IsFiniteFunctions {
             return doFunConstant(vec, RRuntime.LOGICAL_TRUE);
         }
 
-        @Specialization(contains = "doComplete")
+        @Specialization(replaces = "doComplete")
         protected RLogicalVector doIsFinite(RAbstractLogicalVector vec) {
             return doFunLogical(vec, value -> !RRuntime.isNA(value));
         }
@@ -166,6 +170,10 @@ public class IsFiniteFunctions {
     @RBuiltin(name = "is.infinite", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsInfinite extends Adapter {
 
+        static {
+            Casts.noCasts(IsInfinite.class);
+        }
+
         @Specialization
         protected RLogicalVector doIsInfinite(RAbstractDoubleVector vec) {
             return doFunDouble(vec, Double::isInfinite);
@@ -190,6 +198,10 @@ public class IsFiniteFunctions {
     @RBuiltin(name = "is.nan", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsNaN extends Adapter {
 
+        static {
+            Casts.noCasts(IsNaN.class);
+        }
+
         private static boolean isNaN(double value) {
             return Double.isNaN(value) && !RRuntime.isNA(value);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java
index f7e53501ecb610c53a12c010ad8830382a539cde..48cc21c9563ce13f760332e53ca650e2e6a15229 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsListFactor.java
@@ -19,7 +19,6 @@ 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.nodes.Node;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.IsListFactorNodeGen.IsListFactorInternalNodeGen;
 import com.oracle.truffle.r.nodes.unary.IsFactorNode;
@@ -70,8 +69,8 @@ public abstract class IsListFactor extends RBuiltinNode {
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IsListFactor.class);
         casts.arg("recursive").asLogicalVector().findFirst().map(toBoolean());
     }
 
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 4a85c00052164f5c2ea76442cfab799fb2cdf6ea..39826ee9a75c775a6871bc9507ca43461c737a52 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,10 @@ public abstract class IsNA extends RBuiltinNode {
 
     private final ConditionProfile nullDimNamesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(IsNA.class);
+    }
+
     private Object isNARecursive(Object o) {
         if (recursiveIsNA == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java
index f4b26fcf8a8cb22d73345c7efde39196de4dd194..d4939ab3a5e1d9e3e3688d6edfa20ed44bac55c5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
 @RBuiltin(name = "isS4", kind = PRIMITIVE, parameterNames = {"object"}, behavior = PURE)
 public abstract class IsS4 extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(IsS4.class);
+    }
+
     public abstract byte execute(Object value);
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsSingle.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsSingle.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9d87fff252c7bacefbbd5f4d62d4bb676fcc283
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsSingle.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base;
+
+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.Specialization;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+
+@RBuiltin(name = "is.single", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
+public abstract class IsSingle extends RBuiltinNode {
+
+    static {
+        Casts casts = new Casts(IsSingle.class);
+        casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENTS_PASSED, 0, "'is.single'", 1);
+    }
+
+    @Specialization
+    protected Object isSingle(@SuppressWarnings("unused") Object x) {
+        throw RError.error(this, RError.Message.UNIMPLEMENTED_TYPE_IN_R, "single");
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
index bc49575eb2215a6c18979df1bec75c80252e7d80..4c096d94e544f306d1444830bd1abf3bd7affa2e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
@@ -32,16 +32,12 @@ 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.nodes.Node.Child;
 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.ValueProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 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.SpecialAttributesFunctionsFactory.GetDimAttributeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -66,24 +62,29 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * Handles all builtin functions of the form {@code is.xxx}, where is {@code xxx} is a "type".
  */
-@SuppressWarnings("unused")
 public class IsTypeFunctions {
 
     protected abstract static class MissingAdapter extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("x").conf(c -> c.allowNull().mustNotBeMissing(null, RError.Message.ARGUMENT_MISSING, "x"));
+        protected static Casts createCasts(Class<? extends MissingAdapter> extCls) {
+            Casts casts = new Casts(extCls);
+            casts.arg("x").mustNotBeMissing((RBaseNode) null, RError.Message.ARGUMENT_MISSING, "x");
+            return casts;
         }
     }
 
     @RBuiltin(name = "is.array", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsArray extends MissingAdapter {
 
+        static {
+            createCasts(IsArray.class);
+        }
+
         private final ConditionProfile isArrayProfile = ConditionProfile.createBinaryProfile();
         @Child private GetDimAttributeNode getDim = GetDimAttributeNodeGen.create();
 
@@ -95,7 +96,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRAbstractVector(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -103,18 +104,22 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.recursive", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsRecursive extends MissingAdapter {
 
+        static {
+            createCasts(IsRecursive.class);
+        }
+
         @Specialization
-        protected byte isRecursive(RNull arg) {
+        protected byte isRecursive(@SuppressWarnings("unused") RNull arg) {
             return RRuntime.LOGICAL_FALSE;
         }
 
         @Specialization(guards = {"!isRList(arg)", "!isRExpression(arg)"})
-        protected byte isRecursive(RAbstractVector arg) {
+        protected byte isRecursive(@SuppressWarnings("unused") RAbstractVector arg) {
             return RRuntime.LOGICAL_FALSE;
         }
 
         @Specialization
-        protected byte isRecursive(RListBase arg) {
+        protected byte isRecursive(@SuppressWarnings("unused") RListBase arg) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -123,7 +128,7 @@ public class IsTypeFunctions {
         }
 
         @Fallback
-        protected byte isRecursiveFallback(Object value) {
+        protected byte isRecursiveFallback(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_TRUE;
         }
     }
@@ -133,13 +138,17 @@ public class IsTypeFunctions {
 
         @Child private InheritsCheckNode inheritsFactorCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR);
 
+        static {
+            createCasts(IsAtomic.class);
+        }
+
         @Specialization
-        protected byte isAtomic(RNull arg) {
+        protected byte isAtomic(@SuppressWarnings("unused") RNull arg) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRList(arg)", "!isRExpression(arg)"})
-        protected byte isAtomic(RAbstractVector arg) {
+        protected byte isAtomic(@SuppressWarnings("unused") RAbstractVector arg) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -153,7 +162,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRNull(value)", "!isFactor(value)", "!isNonListVector(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -161,13 +170,17 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.call", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsCall extends MissingAdapter {
 
+        static {
+            createCasts(IsCall.class);
+        }
+
         @Specialization
-        protected byte isType(RLanguage lang) {
+        protected byte isType(@SuppressWarnings("unused") RLanguage lang) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRLanguage(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -175,8 +188,12 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.character", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsCharacter extends MissingAdapter {
 
+        static {
+            createCasts(IsCharacter.class);
+        }
+
         @Specialization
-        protected byte isType(RAbstractStringVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractStringVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -185,7 +202,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isAnyCharacter(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -193,8 +210,12 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.complex", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsComplex extends MissingAdapter {
 
+        static {
+            createCasts(IsComplex.class);
+        }
+
         @Specialization
-        protected byte isType(RAbstractComplexVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractComplexVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -203,7 +224,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isAnyComplex(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -211,8 +232,12 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.double", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsDouble extends MissingAdapter {
 
+        static {
+            createCasts(IsDouble.class);
+        }
+
         @Specialization
-        protected byte isType(RAbstractDoubleVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractDoubleVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -221,7 +246,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isAnyDouble(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -229,13 +254,17 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.expression", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsExpression extends MissingAdapter {
 
+        static {
+            createCasts(IsExpression.class);
+        }
+
         @Specialization
-        protected byte isType(RExpression expr) {
+        protected byte isType(@SuppressWarnings("unused") RExpression expr) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRExpression(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -243,13 +272,17 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsFunction extends MissingAdapter {
 
+        static {
+            createCasts(IsFunction.class);
+        }
+
         @Specialization
-        protected byte isType(RFunction value) {
+        protected byte isType(@SuppressWarnings("unused") RFunction value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRFunction(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -257,8 +290,12 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.integer", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsInteger extends MissingAdapter {
 
+        static {
+            createCasts(IsInteger.class);
+        }
+
         @Specialization
-        protected byte isType(RAbstractIntVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractIntVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -267,30 +304,35 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isAnyInteger(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
 
     @RBuiltin(name = "is.language", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsLanguage extends MissingAdapter {
+
+        static {
+            createCasts(IsLanguage.class);
+        }
+
         @Specialization
-        protected byte isType(RSymbol value) {
+        protected byte isType(@SuppressWarnings("unused") RSymbol value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization
-        protected byte isType(RExpression value) {
+        protected byte isType(@SuppressWarnings("unused") RExpression value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization
-        protected byte isType(RLanguage value) {
+        protected byte isType(@SuppressWarnings("unused") RLanguage value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRSymbol(value)", "!isRExpression(value)", "!isRLanguage(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -298,22 +340,24 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.list", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsList extends MissingAdapter {
 
-        private final ConditionProfile isListProfile = ConditionProfile.createBinaryProfile();
+        static {
+            createCasts(IsList.class);
+        }
 
         public abstract byte execute(Object value);
 
         @Specialization
-        protected byte isType(RList value) {
+        protected byte isType(@SuppressWarnings("unused") RList value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization
-        protected byte isType(RPairList pl) {
+        protected byte isType(@SuppressWarnings("unused") RPairList pl) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRList(value)", "!isRPairList(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -321,8 +365,12 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.logical", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsLogical extends MissingAdapter {
 
+        static {
+            createCasts(IsLogical.class);
+        }
+
         @Specialization
-        protected byte isType(RAbstractLogicalVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractLogicalVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -331,7 +379,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isAnyLogical(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -342,13 +390,17 @@ public class IsTypeFunctions {
         private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile();
         @Child private GetDimAttributeNode getDim = GetDimAttributeNodeGen.create();
 
+        static {
+            createCasts(IsMatrix.class);
+        }
+
         @Specialization
         protected byte isType(RAbstractVector vector) {
             return RRuntime.asLogical(isMatrixProfile.profile(getDim.isMatrix(vector)));
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRAbstractVector(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -356,13 +408,17 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.name", aliases = {"is.symbol"}, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsName extends MissingAdapter {
 
+        static {
+            createCasts(IsName.class);
+        }
+
         @Specialization
-        protected byte isType(RSymbol value) {
+        protected byte isType(@SuppressWarnings("unused") RSymbol value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRSymbol(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -370,18 +426,22 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.numeric", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsNumeric extends MissingAdapter {
 
+        static {
+            createCasts(IsNumeric.class);
+        }
+
         @Specialization(guards = "!isFactor(value)")
-        protected byte isType(RAbstractIntVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractIntVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = "isFactor(value)")
-        protected byte isTypeFactor(RAbstractIntVector value) {
+        protected byte isTypeFactor(@SuppressWarnings("unused") RAbstractIntVector value) {
             return RRuntime.LOGICAL_FALSE;
         }
 
         @Specialization
-        protected byte isType(RAbstractDoubleVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractDoubleVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -390,7 +450,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isAnyNumeric(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
 
@@ -404,13 +464,17 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.null", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsNull extends MissingAdapter {
 
+        static {
+            createCasts(IsNull.class);
+        }
+
         @Specialization
-        protected byte isType(RNull value) {
+        protected byte isType(@SuppressWarnings("unused") RNull value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRNull(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -427,6 +491,10 @@ public class IsTypeFunctions {
 
         @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create();
 
+        static {
+            Casts.noCasts(IsObject.class);
+        }
+
         public abstract byte execute(Object value);
 
         @Specialization
@@ -435,25 +503,30 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRAttributable(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
 
     @RBuiltin(name = "is.pairlist", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsPairList extends MissingAdapter {
+
+        static {
+            createCasts(IsPairList.class);
+        }
+
         @Specialization
-        protected byte isType(RNull value) {
+        protected byte isType(@SuppressWarnings("unused") RNull value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization
-        protected byte isType(RPairList value) {
+        protected byte isType(@SuppressWarnings("unused") RPairList value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isRNull(value)", "!isRPairList(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -461,8 +534,12 @@ public class IsTypeFunctions {
     @RBuiltin(name = "is.raw", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
     public abstract static class IsRaw extends MissingAdapter {
 
+        static {
+            createCasts(IsRaw.class);
+        }
+
         @Specialization
-        protected byte isType(RAbstractRawVector value) {
+        protected byte isType(@SuppressWarnings("unused") RAbstractRawVector value) {
             return RRuntime.LOGICAL_TRUE;
         }
 
@@ -471,7 +548,7 @@ public class IsTypeFunctions {
         }
 
         @Specialization(guards = {"!isRMissing(value)", "!isAnyRaw(value)"})
-        protected byte isType(Object value) {
+        protected byte isType(@SuppressWarnings("unused") Object value) {
             return RRuntime.LOGICAL_FALSE;
         }
     }
@@ -482,13 +559,12 @@ public class IsTypeFunctions {
         private final ConditionProfile attrNull = ConditionProfile.createBinaryProfile();
         private final ConditionProfile attrEmpty = ConditionProfile.createBinaryProfile();
         private final ConditionProfile attrNames = ConditionProfile.createBinaryProfile();
-        private final BranchProfile namesAttrProfile = BranchProfile.create();
         @Child private GetFixedAttributeNode namesGetter = GetFixedAttributeNode.createNames();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("x").conf(c -> c.allowNull().mustNotBeMissing(null, RError.Message.ARGUMENT_MISSING, "x"));
-            casts.arg("mode").defaultError(this, RError.Message.INVALID_ARGUMENT, "mode").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
+        static {
+            Casts casts = new Casts(IsVector.class);
+            casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x");
+            casts.arg("mode").defaultError(RError.Message.INVALID_ARGUMENT, "mode").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
 
         @TruffleBoundary
@@ -497,8 +573,8 @@ public class IsTypeFunctions {
         }
 
         @Specialization(limit = "5", guards = "cachedMode == mode")
-        protected byte isVectorCached(RAbstractVector x, String mode,
-                        @Cached("mode") String cachedMode,
+        protected byte isVectorCached(RAbstractVector x, @SuppressWarnings("unused") String mode,
+                        @Cached("mode") @SuppressWarnings("unused") String cachedMode,
                         @Cached("typeFromMode(mode)") RType type) {
             if (namesOnlyOrNoAttr(x) && (type == RType.Any || x.getRType() == type)) {
                 return RRuntime.LOGICAL_TRUE;
@@ -507,13 +583,13 @@ public class IsTypeFunctions {
             }
         }
 
-        @Specialization(contains = "isVectorCached")
+        @Specialization(replaces = "isVectorCached")
         protected byte isVector(RAbstractVector x, String mode) {
             return isVectorCached(x, mode, mode, typeFromMode(mode));
         }
 
         @Fallback
-        protected byte isVector(Object x, Object mode) {
+        protected byte isVector(@SuppressWarnings("unused") Object x, @SuppressWarnings("unused") Object mode) {
             return RRuntime.LOGICAL_FALSE;
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
index c26d7aa2866a30655490715367d1d56eedab22cf..cb571f301f697837038db0d26a26d078740e1dfd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsUnsorted.java
@@ -31,7 +31,6 @@ 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.binary.BinaryMapBooleanFunctionNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.Order.CmpNode;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.CmpNodeGen;
@@ -55,8 +54,8 @@ public abstract class IsUnsorted extends RBuiltinNode {
 
     private final ConditionProfile strictlyProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(IsUnsorted.class);
         casts.arg("strictly").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).notNA().map(toBoolean());
     }
 
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 41691b554b1a5521b91e3c006b5793578df1c485..1a27658726297e3ad2473785115c172a18586063 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
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa
 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;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNodeGen;
@@ -87,10 +86,11 @@ public class LaFunctions {
         protected static final String[] NAMES = new String[]{"values", "vectors"};
         protected final BranchProfile errorProfile = BranchProfile.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        protected static Casts createCasts(Class<? extends RsgAdapter> extClass) {
+            Casts casts = new Casts(extClass);
             casts.arg("matrix").asDoubleVector(false, true, false).mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_NUMERIC, "x");
             casts.arg("onlyValues").defaultError(RError.Message.INVALID_ARGUMENT, "only.values").asLogicalVector().findFirst().notNA().map(toBoolean());
+            return casts;
         }
     }
 
@@ -99,6 +99,10 @@ public class LaFunctions {
 
         private final ConditionProfile hasComplexValues = ConditionProfile.createBinaryProfile();
 
+        static {
+            createCasts(Rg.class);
+        }
+
         @Specialization
         protected Object doRg(RDoubleVector matrix, boolean onlyValues,
                         @Cached("create()") GetDimAttributeNode getDimsNode) {
@@ -193,6 +197,11 @@ public class LaFunctions {
 
     @RBuiltin(name = "La_rs", kind = INTERNAL, parameterNames = {"matrix", "onlyValues"}, behavior = PURE)
     public abstract static class Rs extends RsgAdapter {
+
+        static {
+            createCasts(Rs.class);
+        }
+
         @Specialization
         protected Object doRs(RDoubleVector matrix, boolean onlyValues,
                         @Cached("create()") GetDimAttributeNode getDimsNode) {
@@ -255,8 +264,8 @@ public class LaFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Qr.class);
             casts.arg("in").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a");
         }
 
@@ -311,8 +320,8 @@ public class LaFunctions {
         private static final char SIDE = 'L';
         private static final char TRANS = 'T';
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(QrCoefReal.class);
             casts.arg("q").mustBe(instanceOf(RList.class));
             casts.arg("b").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "b");
         }
@@ -379,19 +388,11 @@ public class LaFunctions {
 
         @Child private SetFixedAttributeNode setLogAttrNode = SetFixedAttributeNode.create("logarithm");
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg("a").asDoubleVector(false, true, false).
-                mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").
-                mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a");
-
-            casts.arg("uselog").defaultError(RError.Message.MUST_BE_LOGICAL, "logarithm").
-                asLogicalVector().
-                findFirst().
-                notNA().
-                map(toBoolean());
-            //@formatter:on
+        static {
+            Casts casts = new Casts(DetGeReal.class);
+            casts.arg("a").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a");
+
+            casts.arg("uselog").defaultError(RError.Message.MUST_BE_LOGICAL, "logarithm").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
         @Specialization
@@ -465,22 +466,14 @@ public class LaFunctions {
         @Child private SetFixedAttributeNode setPivotAttrNode = SetFixedAttributeNode.create("pivot");
         @Child private SetFixedAttributeNode setRankAttrNode = SetFixedAttributeNode.create("rank");
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg("a").asDoubleVector(false, true, false).
-                mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").
-                mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a").
-                mustBe(dimGt(1, 0), RError.Message.DIMS_GT_ZERO, "a");
-
-            casts.arg("pivot").asLogicalVector().
-                findFirst().
-                notNA().
-                map(toBoolean());
-
-            casts.arg("tol").asDoubleVector().
-                findFirst(RRuntime.DOUBLE_NA);
-            //@formatter:on
+        static {
+            Casts casts = new Casts(LaChol.class);
+            casts.arg("a").asDoubleVector(false, true, false).mustBe(matrix(), RError.Message.MUST_BE_NUMERIC_MATRIX, "a").mustBe(squareMatrix(), RError.Message.MUST_BE_SQUARE_MATRIX, "a").mustBe(
+                            dimGt(1, 0), RError.Message.DIMS_GT_ZERO, "a");
+
+            casts.arg("pivot").asLogicalVector().findFirst().notNA().map(toBoolean());
+
+            casts.arg("tol").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
         }
 
         @Specialization
@@ -541,19 +534,14 @@ public class LaFunctions {
             return vec -> vec.getDimensions()[dim];
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            //@formatter:off
-            casts.arg("a").mustBe(numericValue()).asVector().
-                mustBe(matrix(), RError.ROOTNODE, RError.Message.MUST_BE_NUMERIC_MATRIX, "a").
-                mustBe(not(dimEq(0, 0)), RError.ROOTNODE, RError.Message.GENERIC, "'a' is 0-diml").
-                mustBe(squareMatrix(), RError.ROOTNODE, RError.Message.MUST_BE_SQUARE_MATRIX_SPEC, "a", getDimVal(0), getDimVal(1));
+        static {
+            Casts casts = new Casts(LaSolve.class);
+            casts.arg("a").mustBe(numericValue()).asVector().mustBe(matrix(), RError.ROOTNODE, RError.Message.MUST_BE_NUMERIC_MATRIX, "a").mustBe(not(dimEq(0, 0)), RError.ROOTNODE,
+                            RError.Message.GENERIC, "'a' is 0-diml").mustBe(squareMatrix(), RError.ROOTNODE, RError.Message.MUST_BE_SQUARE_MATRIX_SPEC, "a", getDimVal(0), getDimVal(1));
 
-            casts.arg("bin").asDoubleVector(false, true, false).
-                mustBe(or(not(matrix()), not(dimEq(1, 0))), RError.ROOTNODE, RError.Message.GENERIC, "no right-hand side in 'b'");
+            casts.arg("bin").asDoubleVector(false, true, false).mustBe(or(not(matrix()), not(dimEq(1, 0))), RError.ROOTNODE, RError.Message.GENERIC, "no right-hand side in 'b'");
 
             casts.arg("tolin").asDoubleVector().findFirst(RRuntime.DOUBLE_NA);
-            //@formatter:on
         }
 
         @Specialization
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 89f801a70361845bad538f6c77da4d512dd7b1fa..a3bb7941e9bcef3db6f36feceea98a7c45e1d417 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,7 +33,6 @@ 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;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
@@ -70,8 +69,8 @@ public abstract class Lapply extends RBuiltinNode {
 
     @Child private LapplyInternalNode lapply = LapplyInternalNodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Lapply.class);
         // to make conversion of X parameter 100% correct, we'd need to match semantics of
         // asVector() to whatever GNU R is doing there; still this can be a problem only if the
         // internal is called directly (otherwise, it's guaranteed that it's a vector)
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java
index ae8bc8706610f1c9b9087e945d8707c5491ae08f..df92d3e9fa020cb62fbb1f1212cde43b66c9597d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Length.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,10 @@ public abstract class Length extends RBuiltinNode {
 
     public abstract int executeInt(VirtualFrame frame, Object vector);
 
+    static {
+        Casts.noCasts(Length.class);
+    }
+
     @Specialization
     protected int getLength(VirtualFrame frame, Object vector,
                     @Cached("create()") RLengthNode lengthNode) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java
index e8b4549af008e25a149ead00af1308ddcf1f608f..3b1cff197bee5ae5be5da149591f407b40afd91a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lengths.java
@@ -36,7 +36,6 @@ 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.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -52,8 +51,8 @@ public abstract class Lengths extends RBuiltinNode {
 
     @Child private RLengthNode lengthNode;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Lengths.class);
         casts.arg("x").defaultError(RError.SHOW_CALLER, X_LIST_ATOMIC).allowNull().mustBe(abstractVectorValue());
         casts.arg("use.names").mustBe(numericValue(), RError.SHOW_CALLER, INVALID_VALUE, "use.names").asLogicalVector().findFirst().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/List2Env.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/List2Env.java
index e87f6b36855705860fc21fba64a5dc51b231f37f..f1ab5acbb72b74e7146af06404d35b25accf3af4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/List2Env.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/List2Env.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Cached;
 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.nodes.builtin.RList2EnvNode;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -37,8 +36,9 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "list2env", kind = INTERNAL, parameterNames = {"x", "envir"}, behavior = PURE)
 public abstract class List2Env extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(List2Env.class);
         casts.arg("x").mustBe(RAbstractListVector.class, Message.FIRST_ARGUMENT_NOT_NAMED_LIST);
         casts.arg("envir").mustBe(REnvironment.class, Message.MUST_BE_ENVIRON, "envir");
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
index 2d945ceecfa1af3c142ced1274a1f83b73471621..e7ffa8d42c2de6915c99b212b0c5fb163ef5556a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java
@@ -53,6 +53,10 @@ public abstract class ListBuiltin extends RBuiltinNode {
 
     @CompilationFinal private RStringVector suppliedSignatureArgNames;
 
+    static {
+        Casts.noCasts(ListBuiltin.class);
+    }
+
     /**
      * Creates a shared permanent vector so that it can be re-used for every list(...) with the same
      * arguments.
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java
index c607fbbbf5844b16a494cde7b44f4b1c77185f70..462f900017a3c52b5ccfb872e0bb94b38b29d762 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadSaveFunctions.java
@@ -31,7 +31,6 @@ 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.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.SerializeFunctions.Adapter;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode;
@@ -60,8 +59,8 @@ public class LoadSaveFunctions {
 
         private final NACheck naCheck = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(LoadFromConn2.class);
             casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
             casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
             casts.arg("verbose").asLogicalVector().findFirst().map(toBoolean());
@@ -117,8 +116,8 @@ public class LoadSaveFunctions {
     public abstract static class Load extends RBuiltinNode {
         // now deprecated but still used by some packages
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Load.class);
             casts.arg("file").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.FIRST_ARGUMENT_NOT_FILENAME).findFirst();
             casts.arg("envir").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
         }
@@ -194,10 +193,10 @@ public class LoadSaveFunctions {
         private static final String ASCII_HEADER = "RDA2\n";
         private static final String XDR_HEADER = "RDX2\n";
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("list").mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.FIRST_ARGUMENT_NOT_CHARVEC).findFirst();
-            ConnectionFunctions.Casts.connection(casts);
+        static {
+            Casts casts = new Casts(SaveToConn.class);
+            casts.arg("list").mustBe(stringValue()).asStringVector();
+            ConnectionFunctions.CastsHelper.connection(casts);
             casts.arg("ascii").mustBe(logicalValue(), RError.Message.ASCII_NOT_LOGICAL);
             casts.arg("version").allowNull().mustBe(integerValue());
             casts.arg("environment").mustNotBeNull(RError.Message.USE_NULL_ENV_DEFUNCT).mustBe(instanceOf(REnvironment.class));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java
index 8e5625638866c182b9141f0437aa58b8aaadfb5f..29231259c8f30c438b3372b0a2074bc5bec39946 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LocaleFunctions.java
@@ -38,7 +38,7 @@ import java.nio.charset.Charset;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -55,9 +55,9 @@ public class LocaleFunctions {
     @RBuiltin(name = "Sys.getlocale", kind = INTERNAL, parameterNames = {"category"}, behavior = READS_STATE)
     public abstract static class GetLocale extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.category(casts);
+        static {
+            Casts casts = new Casts(GetLocale.class);
+            CastsHelper.category(casts);
         }
 
         @Specialization
@@ -93,9 +93,9 @@ public class LocaleFunctions {
     @RBuiltin(name = "Sys.setlocale", kind = INTERNAL, parameterNames = {"category", "locale"}, behavior = MODIFIES_STATE)
     public abstract static class SetLocale extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.category(casts);
+        static {
+            Casts casts = new Casts(SetLocale.class);
+            CastsHelper.category(casts);
             casts.arg("locale").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
 
@@ -134,9 +134,10 @@ public class LocaleFunctions {
 
     @RBuiltin(name = "enc2native", kind = PRIMITIVE, parameterNames = "x", behavior = READS_STATE)
     public abstract static class Enc2Native extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.xCharacterVector(casts);
+
+        static {
+            Casts casts = new Casts(Enc2Native.class);
+            CastsHelper.xCharacterVector(casts);
         }
 
         @Specialization
@@ -148,9 +149,10 @@ public class LocaleFunctions {
 
     @RBuiltin(name = "enc2utf8", kind = PRIMITIVE, parameterNames = "x", behavior = READS_STATE)
     public abstract static class Enc2Utf8 extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.xCharacterVector(casts);
+
+        static {
+            Casts casts = new Casts(Enc2Utf8.class);
+            CastsHelper.xCharacterVector(casts);
         }
 
         @Specialization
@@ -162,8 +164,9 @@ public class LocaleFunctions {
 
     @RBuiltin(name = "bindtextdomain", kind = PRIMITIVE, parameterNames = {"domain", "dirname"}, behavior = READS_STATE)
     public abstract static class BindTextDomain extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(BindTextDomain.class);
             casts.arg("domain").mustBe(stringValue(), INVALID_VALUE, "domain");
         }
 
@@ -175,12 +178,12 @@ public class LocaleFunctions {
         }
     }
 
-    private static final class Casts {
-        private static void xCharacterVector(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void xCharacterVector(Casts casts) {
             casts.arg("x").mustBe(stringValue(), ARGUMENT_NOT_CHAR_VECTOR);
         }
 
-        private static void category(CastBuilder casts) {
+        private static void category(Casts casts) {
             casts.arg("category").mustBe(numericValue(), NO_CALLER, INVALID_ARGUMENT, "category").asIntegerVector().findFirst();
         }
     }
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 457eca9da958eace8975e6ec36c6fb2cd25d90ca..e157019c8ea7564e0119b7875b9e47372a949452 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@ 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;
 import com.oracle.truffle.r.runtime.RError;
@@ -62,8 +61,8 @@ public class LogFunctions {
             return new Object[]{RMissing.instance, Math.E};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
             casts.arg("base").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue()).asDoubleVector().findFirst();
         }
@@ -141,8 +140,8 @@ public class LogFunctions {
 
         private static final double LOG_10 = Math.log(10);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log10.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -168,8 +167,8 @@ public class LogFunctions {
 
         private static final double LOG_2 = Math.log(2);
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log2.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -193,8 +192,8 @@ public class LogFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Log1p.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java
index aa4568846a3fcc0d798e8ef1ccb5e2efb9214e6a..0e05ca0385180b335d401f4dabb5fd5e165e474e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Ls.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RStringVector;
@@ -39,8 +38,8 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 @RBuiltin(name = "ls", aliases = {"objects"}, kind = INTERNAL, parameterNames = {"envir", "all.names", "sorted"}, behavior = PURE)
 public abstract class Ls extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Ls.class);
         casts.arg("envir").mustBe(REnvironment.class, NO_CALLER, INVALID_ARGUMENT, "envir");
         casts.arg("all.names").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("sorted").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java
index 60c4ed1f56c3e6b0dcb6761445537868d2edd2b3..d1ac331fb5721d96bba15d982ce41211767f2174 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeNames.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -46,8 +45,8 @@ public abstract class MakeNames extends RBuiltinNode {
     private final ConditionProfile namesLengthZero = ConditionProfile.createBinaryProfile();
     private final NACheck dummyCheck = NACheck.create(); // never triggered (used for vector update)
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(MakeNames.class);
         casts.arg("names").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER_NAMES);
         casts.arg("allow_").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "allow_").asLogicalVector().findFirst().mustBe(notLogicalNA());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java
index ac65cdbbd8f45aad3086052a56b11873450e0926..9a0d72178e8784e0a2d6cf9ef82a6272f66e6b0a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -45,9 +44,9 @@ public abstract class MakeUnique extends RBuiltinNode {
     private final ConditionProfile duplicatesProfile = ConditionProfile.createBinaryProfile();
     private final NACheck dummyCheck = NACheck.create(); // never triggered (used for vector update)
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("names").defaultError(RError.SHOW_CALLER, RError.Message.NOT_CHARACTER_VECTOR, "names").mustNotBeNull().mustBe(stringValue());
+    static {
+        Casts casts = new Casts(MakeUnique.class);
+        casts.arg("names").defaultError(RError.SHOW_CALLER, RError.Message.NOT_CHARACTER_VECTOR, "names").mustBe(stringValue());
         casts.arg("sep").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_STRING, "sep").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
 
     }
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 a71c27e486613d27c3e58d720bbf888a696ac62a..f51a45e0d95e883c1f8039ad0b950dd30f8a2e07 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
@@ -30,21 +30,19 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
-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;
 import com.oracle.truffle.r.nodes.builtin.base.infix.Subscript;
 import com.oracle.truffle.r.nodes.builtin.base.infix.SubscriptNodeGen;
 import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
 import com.oracle.truffle.r.runtime.AnonymousFrameVariable;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -68,8 +66,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 @RBuiltin(name = "mapply", kind = INTERNAL, parameterNames = {"FUN", "dots", "MoreArgs"}, splitCaller = true, behavior = COMPLEX)
 public abstract class Mapply extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Mapply.class);
         // let's assume that mapply internal is never called directly, otherwise all hell ensues -
         // even in GNU R .Internal(mapply(rep, 1:4, NULL)) causes a segfault
         casts.arg("FUN").mustBe(instanceOf(RFunction.class));
@@ -90,7 +88,7 @@ public abstract class Mapply extends RBuiltinNode {
             this.vectorElementName = "*" + AnonymousFrameVariable.create(vectorElementName);
             this.lengthNode = insert(LengthNodeGen.create());
             this.indexedLoadNode = insert(SubscriptNodeGen.create());
-            this.writeVectorElementNode = insert(WriteVariableNode.createAnonymous(this.vectorElementName, null, Mode.REGULAR));
+            this.writeVectorElementNode = insert(WriteVariableNode.createAnonymous(this.vectorElementName, Mode.REGULAR, null));
             this.argName = argName;
         }
     }
@@ -104,9 +102,8 @@ public abstract class Mapply extends RBuiltinNode {
         return RDataFactory.createList(result);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object mApply(VirtualFrame frame, RFunction fun, RAbstractListVector dots, RNull moreArgs) {
+    protected Object mApply(VirtualFrame frame, RFunction fun, RAbstractListVector dots, @SuppressWarnings("unused") RNull moreArgs) {
         return mApply(frame, fun, dots, RDataFactory.createList());
     }
 
@@ -195,13 +192,11 @@ public abstract class Mapply extends RBuiltinNode {
             return result;
         }
 
-        @Specialization(contains = "cachedMApply")
+        @Specialization(replaces = "cachedMApply")
         protected Object[] mApply(VirtualFrame frame, RAbstractListVector dots, RFunction function, RAbstractListVector moreArgs,
-                        @SuppressWarnings("unused") @Cached("createArgsIdentifier()") Object argsIdentifier,
-                        @Cached("createFrameSlotNode(argsIdentifier)") FrameSlotNode slotNode,
                         @Cached("create()") RLengthNode lengthNode,
                         @Cached("createIndexedLoadNode()") Subscript indexedLoadNode,
-                        @Cached("createExplicitCallNode(argsIdentifier)") RCallNode callNode) {
+                        @Cached("create()") RExplicitCallNode callNode) {
             int dotsLength = dots.getLength();
             int moreArgsLength = moreArgs.getLength();
             int[] lengths = new int[dotsLength];
@@ -235,9 +230,7 @@ public abstract class Mapply extends RBuiltinNode {
                     values[listIndex] = vecElement;
                 }
                 /* Now call the function */
-                FrameSlot frameSlot = slotNode.executeFrameSlot(frame);
-                frame.setObject(frameSlot, new RArgsValuesAndNames(values, signature));
-                result[i] = callNode.execute(frame, function);
+                result[i] = callNode.execute(frame, function, new RArgsValuesAndNames(values, signature));
             }
             return result;
         }
@@ -272,18 +265,6 @@ public abstract class Mapply extends RBuiltinNode {
             return elementNodes;
         }
 
-        protected Object createArgsIdentifier() {
-            return new Object();
-        }
-
-        protected FrameSlotNode createFrameSlotNode(Object argsIdentifier) {
-            return FrameSlotNode.createTemp(argsIdentifier, true);
-        }
-
-        protected RCallNode createExplicitCallNode(Object argsIdentifier) {
-            return RCallNode.createExplicitCall(argsIdentifier);
-        }
-
         protected Subscript createIndexedLoadNode() {
             return SubscriptNodeGen.create();
         }
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 7bee0fa552fc045332ea15babf8bdaa0daca15f6..88b10299f854ef5895632bc713867b51b4b27706 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -84,6 +84,10 @@ public abstract class MatMult extends RBuiltinNode {
 
     private final NACheck na;
 
+    static {
+        Casts.noCasts(MatMult.class);
+    }
+
     public MatMult(boolean promoteDimNames) {
         this.promoteDimNames = promoteDimNames;
         this.na = NACheck.create();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
index b950ea128f04fbab771e66aa9734749ec98aa9a0..291aad6c297e6276d231df73417c2083fb91badd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
@@ -33,7 +33,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.nodes.helpers.RFactorNodes;
@@ -73,8 +72,8 @@ public abstract class Match extends RBuiltinNode {
     private final NACheck naCheck = NACheck.create();
     private final ConditionProfile bigTableProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Match.class);
         // TODO initially commented out because of use of scalars, the commented out version
         // converted to new cast pipelines API
 
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
index bc6405b87dad17cc3a56e2b301868c6686a84bbc..170e79418089d9fad4aabc809aa050a0bbc45eae 100644
--- 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,6 +65,10 @@ 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 {
 
+    static {
+        Casts.noCasts(MatchArg.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
@@ -80,7 +84,7 @@ public abstract class MatchArg extends RBuiltinNode {
 
         {
             CastBuilder builder = new CastBuilder();
-            builder.arg(0).allowNull().asStringVector();
+            builder.arg(0).asStringVector();
             builder.arg(1).allowMissing().mustBe(stringValue()).asStringVector();
             builder.arg(2).mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean());
             this.casts = builder.getCasts();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
index 38db2c425fdbe62e2f9ba62b14e69ede7eb20b09..69cb73a3f14f1f5e8d862ff172407a8c3ef575dc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchFun.java
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.MatchFunNodeGen.MatchFunInternalNodeGen;
 import com.oracle.truffle.r.nodes.function.GetCallerFrameNode;
@@ -65,8 +64,8 @@ public abstract class MatchFun extends RBuiltinNode {
         return new Object[]{RMissing.instance, RRuntime.LOGICAL_TRUE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(MatchFun.class);
         casts.arg("descend").asLogicalVector().findFirst().map(toBoolean());
     }
 
@@ -131,7 +130,7 @@ public abstract class MatchFun extends RBuiltinNode {
             return checkResult(lookup.execute(frame, getCallerFrame.execute(frame)));
         }
 
-        @Specialization(contains = "matchfunCached", guards = {"funValue.getLength() == 1"})
+        @Specialization(replaces = "matchfunCached", guards = {"funValue.getLength() == 1"})
         protected RFunction matchfunGeneric(VirtualFrame frame, @SuppressWarnings("unused") RPromise funPromise, RAbstractStringVector funValue, boolean descend) {
             return checkResult(slowPathLookup(funValue.getDataAt(0), getCallerFrame.execute(frame), descend));
         }
@@ -144,7 +143,7 @@ public abstract class MatchFun extends RBuiltinNode {
             return checkResult(lookup.execute(frame, getCallerFrame.execute(frame)));
         }
 
-        @Specialization(contains = "matchfunCached")
+        @Specialization(replaces = "matchfunCached")
         protected RFunction matchfunGeneric(VirtualFrame frame, @SuppressWarnings("unused") RPromise funPromise, RSymbol funValue, boolean descend) {
             return checkResult(slowPathLookup(funValue.getName(), getCallerFrame.execute(frame), descend));
         }
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 45ca370e1f58679ad502a6889f47e8f939f8b90d..90f7823259a653c13679dd74346ac6f428e2ee77 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
@@ -33,7 +33,6 @@ 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;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -66,8 +65,8 @@ public abstract class Matrix extends RBuiltinNode {
         return (RAbstractVector) updateDimNames.executeRAbstractContainer(vector, o);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Matrix.class);
         casts.arg("data").asVector().mustBe(instanceOf(RAbstractVector.class));
         casts.arg("nrow").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
         casts.arg("ncol").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java
index 87af6c78a00152a5ac0b6e01cb3841e8dc255ab2..2e898cf52915435168f803976d8ac0e8abf10098 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Max.java
@@ -29,7 +29,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode.ReduceSemantics;
@@ -48,8 +47,8 @@ public abstract class Max extends RBuiltinNode {
 
     @Child private UnaryArithmeticReduceNode reduce = UnaryArithmeticReduceNodeGen.create(semantics, BinaryArithmetic.MAX);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Max.class);
         casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
@@ -63,7 +62,7 @@ public abstract class Max extends RBuiltinNode {
         return reduce.executeReduce(args.getArgument(0), naRm, false);
     }
 
-    @Specialization(contains = "maxLengthOne")
+    @Specialization(replaces = "maxLengthOne")
     protected Object max(RArgsValuesAndNames args, boolean naRm,
                     @Cached("create()") Combine combine) {
         return reduce.executeReduce(combine.executeCombine(args, false), naRm, false);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
index c0c491b677d2d3be59592d06eab2ffe3546cd04f..dc04a0b92877a108aaf3d35057386b54bf16a0c8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,10 @@ public abstract class Mean extends RBuiltinNode {
     @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation();
     @Child private BinaryArithmetic div = BinaryArithmetic.DIV.createOperation();
 
+    static {
+        Casts.noCasts(Mean.class);
+    }
+
     @Specialization
     protected double mean(RAbstractDoubleVector x) {
         if (x.getLength() == 0) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
index cef620df871e6e3f8e62b05bdd1356ff770671c6..45dd58eeec87d84b64950d746ac2e13c585c7000 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
@@ -21,7 +21,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -38,19 +37,19 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "merge", kind = INTERNAL, parameterNames = {"xinds", "yinds", "all.x", "all.y"}, behavior = PURE)
 public abstract class Merge extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Merge.class);
         addIntegerCast(casts, "xinds");
         addIntegerCast(casts, "yinds");
         addLogicalCast(casts, "all.x");
         addLogicalCast(casts, "all.y");
     }
 
-    private static void addIntegerCast(CastBuilder casts, String name) {
+    private static void addIntegerCast(Casts casts, String name) {
         casts.arg(name).mustBe(integerValue()).asIntegerVector().mustBe(notEmpty());
     }
 
-    private static void addLogicalCast(CastBuilder casts, String name) {
+    private static void addLogicalCast(Casts casts, String name) {
         casts.arg(name).defaultError(INVALID_LOGICAL, "all.x").mustBe(numericValue()).asLogicalVector().findFirst().notNA().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java
index bf7926db2930958723b940240d772d759d44ba22..09b73c273d4219428e837d870bca7555e078fdb5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Min.java
@@ -29,7 +29,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode.ReduceSemantics;
@@ -48,8 +47,8 @@ public abstract class Min extends RBuiltinNode {
 
     @Child private UnaryArithmeticReduceNode reduce = UnaryArithmeticReduceNodeGen.create(semantics, BinaryArithmetic.MIN);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Min.class);
         casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
@@ -63,7 +62,7 @@ public abstract class Min extends RBuiltinNode {
         return reduce.executeReduce(args.getArgument(0), naRm, false);
     }
 
-    @Specialization(contains = "minLengthOne")
+    @Specialization(replaces = "minLengthOne")
     protected Object min(RArgsValuesAndNames args, boolean naRm,
                     @Cached("create()") Combine combine) {
         return reduce.executeReduce(combine.executeCombine(args, false), naRm, 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 c2faec1d69a4fca54a7103a68e8e3552c7ac485b..b55927dda5324e900eee919da7ca7562f329fb30 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAt
 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;
@@ -52,8 +51,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "nchar", kind = INTERNAL, parameterNames = {"x", "type", "allowNA", "keepNA"}, behavior = PURE)
 public abstract class NChar extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NChar.class);
         casts.arg("x").allowNull().mapIf(integerValue(), asIntegerVector(), asStringVector(true, false, false));
         casts.arg("type").asStringVector().findFirst();
         casts.arg("allowNA").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java
index 3756b5ba7cf1637a6a183d0d96331197eb16154c..d72cda8937c3980ac6688c9fa9fa908234c52a48 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,27 +29,22 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
-@SuppressWarnings("unused")
 @RBuiltin(name = "ngettext", kind = INTERNAL, parameterNames = {"n", "msg1", "msg2", "domain"}, behavior = COMPLEX)
 public abstract class NGetText extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NGetText.class);
         casts.arg("n").asIntegerVector().findFirst().mustBe(gte0());
-
         casts.arg("msg1").defaultError(RError.Message.MUST_BE_STRING, "msg1").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
-
         casts.arg("msg2").defaultError(RError.Message.MUST_BE_STRING, "msg2").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
-
     }
 
     @Specialization()
-    protected String getText(int n, String msg1, String msg2, Object domain) {
+    protected String getText(int n, String msg1, String msg2, @SuppressWarnings("unused") Object domain) {
         return n == 1 ? msg1 : msg2;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
index c8c192044cd66d4cbdad17fe0fd83c12fcfe2ebf..bfd884b2fb2ec7e60ffaf504df65c2517ab53d7d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ 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.Specialization;
-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;
@@ -39,9 +38,9 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "nzchar", kind = PRIMITIVE, parameterNames = {"x", "keepNA"}, behavior = PURE)
 public abstract class NZChar extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asStringVector();
+    static {
+        Casts casts = new Casts(NZChar.class);
+        casts.arg("x").asStringVector();
         casts.arg("keepNA").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
     }
 
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 55c50f76361cc2080b1c84120370207135a03ece..bb8b0830c7506c448902790900a4480c8fdd82de 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,10 @@ public abstract class Names extends RBuiltinNode {
     private final ConditionProfile hasNames = ConditionProfile.createBinaryProfile();
     @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
 
+    static {
+        Casts.noCasts(Names.class);
+    }
+
     @Specialization
     protected Object getNames(RAbstractContainer container) {
         RStringVector names = getNames.getNames(container);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java
index 2f170e5f6602f6e9a4a95863808fc56e438c5221..276bb1ad32e42b9d1d989880e9a91e1623b1d664 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NamespaceFunctions.java
@@ -29,9 +29,9 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.api.dsl.Fallback;
 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.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -43,17 +43,18 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public class NamespaceFunctions {
 
-    private static final class Casts {
-        private static void name(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void name(Casts casts) {
             casts.arg("name").mustBe(stringValue().or(instanceOf(RSymbol.class)));
         }
     }
 
     @RBuiltin(name = "getRegisteredNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = READS_STATE)
     public abstract static class GetRegisteredNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(GetRegisteredNamespace.class);
+            CastsHelper.name(casts);
         }
 
         @Specialization
@@ -79,9 +80,10 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "isRegisteredNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = READS_STATE)
     public abstract static class IsRegisteredNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(IsRegisteredNamespace.class);
+            CastsHelper.name(casts);
         }
 
         @Specialization
@@ -107,6 +109,11 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "isNamespaceEnv", kind = INTERNAL, parameterNames = {"env"}, behavior = PURE)
     public abstract static class IsNamespaceEnv extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(IsNamespaceEnv.class);
+        }
+
         @Specialization
         protected byte doIsNamespaceEnv(REnvironment env) {
             return RRuntime.asLogical(env.isNamespaceEnv());
@@ -128,9 +135,10 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "registerNamespace", kind = INTERNAL, parameterNames = {"name", "env"}, behavior = MODIFIES_STATE)
     public abstract static class RegisterNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(RegisterNamespace.class);
+            CastsHelper.name(casts);
             casts.arg("env").mustBe(instanceOf(REnvironment.class));
         }
 
@@ -154,9 +162,10 @@ public class NamespaceFunctions {
 
     @RBuiltin(name = "unregisterNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = MODIFIES_STATE)
     public abstract static class UnregisterNamespace extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.name(casts);
+
+        static {
+            Casts casts = new Casts(UnregisterNamespace.class);
+            CastsHelper.name(casts);
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java
index 528fb50198c01634224630cfb5e8082016abbdf5..835eb027f59d1a5151cc2012a0e45205961daee0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NormalizePath.java
@@ -38,7 +38,6 @@ import java.nio.file.NoSuchFileException;
 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.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;
@@ -54,8 +53,8 @@ public abstract class NormalizePath extends RBuiltinNode {
 
     private final ConditionProfile doesNotNeedToWork = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NormalizePath.class);
         casts.arg("path").mustBe(stringValue(), NOT_CHARACTER_VECTOR, "path");
         casts.arg("winslash").defaultError(NOT_CHARACTER_VECTOR, "winslash").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().mustBe(eq("/").or(eq("\\\\")).or(eq("\\")),
                         WRONG_WINSLASH);
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 887b5f16ddffcf1e00cbbf2c895078f4d0b2d013..26a9bc602f80816b142a1cc48a126f4931a60ad7 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
@@ -30,7 +30,6 @@ 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.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -62,8 +61,8 @@ public class NumericalFunctions {
             super(RType.Integer, RError.Message.NON_NUMERIC_MATH, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Abs.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue()));
         }
 
@@ -105,8 +104,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Re.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -148,8 +147,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Im.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -191,8 +190,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Conj.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -224,8 +223,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Mod.class);
             casts.arg("z").defaultError(RError.Message.NON_NUMERIC_ARGUMENT_FUNCTION).mustBe(numericValue().or(complexValue()));
         }
 
@@ -267,8 +266,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sign.class);
             casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue());
         }
 
@@ -295,8 +294,8 @@ public class NumericalFunctions {
             super(RType.Double, RError.Message.NON_NUMERIC_MATH, null);
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sqrt.class);
             casts.arg("x").defaultError(RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue().or(complexValue()));
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
index 3eb6440923f772d5c4ba513b9dda0b2723d8a656..7d3f43e6bb2a7d14564136f1652f7e328f962c3a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.FrameSlotNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RError;
@@ -66,8 +65,8 @@ public abstract class OnExit extends RBuiltinNode {
 
     private final BranchProfile invalidateProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(OnExit.class);
         casts.arg("add").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
     }
 
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 3edeeca12f54968580af52923630e07ef930ebb2..cc56be1bf20ed386310a29862acca11d0e86f77c 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
@@ -37,7 +37,6 @@ 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.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
@@ -65,6 +64,10 @@ public class OptionsFunctions {
 
         private final ConditionProfile argNameNull = ConditionProfile.createBinaryProfile();
 
+        static {
+            Casts.noCasts(Options.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RList options(@SuppressWarnings("unused") RMissing x) {
@@ -191,8 +194,8 @@ public class OptionsFunctions {
     @RBuiltin(name = "getOption", kind = INTERNAL, parameterNames = "x", behavior = READS_STATE)
     public abstract static class GetOption extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(GetOption.class);
             casts.arg("x").defaultError(RError.SHOW_CALLER, RError.Message.MUST_BE_STRING, "x").mustBe(stringValue()).asStringVector().findFirst();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
index 1dde2ca238caaf365de383a0c59043638f1b6ea2..13d246bb06695b34f5661040159aa99ab0dc143e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java
@@ -30,7 +30,6 @@ 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.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RPrecedenceBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.CmpNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.IsAtomicNANodeGen;
@@ -149,8 +148,8 @@ public abstract class Order extends RPrecedenceBuiltinNode {
         return (RAbstractVector) castVector2.execute(value);
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Order.class);
         casts.arg("na.last").mustBe(numericValue(), INVALID_LOGICAL, "na.last").asLogicalVector().findFirst();
         casts.arg("decreasing").mustBe(numericValue(), INVALID_LOGICAL, "decreasing").asLogicalVector().findFirst().map(toBoolean());
     }
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 ad4cbd55f2405b4a34761c15835f1a5b45127e3f..55db842837ac8f3b41d9f6ae52666592b76d78dc 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-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;
@@ -45,8 +44,8 @@ public abstract class PMatch extends RBuiltinNode {
 
     public abstract RIntVector execute(RAbstractStringVector x, RAbstractStringVector table, int nomatch, boolean duplicatesOk);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(PMatch.class);
         casts.arg("x").asStringVector();
         casts.arg("table").asStringVector();
         casts.arg("nomatch").mapNull(constant(RRuntime.INT_NA)).asIntegerVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java
index 3dc425ca9cd3f1eb88f88c50847d5825fdde8b06..0614dd2f282a2bf7b37a984e4a075a2b8d7771b5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java
@@ -35,7 +35,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.PMinMaxNodeGen.MultiElemStringHandlerNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
@@ -90,9 +89,10 @@ public abstract class PMinMax extends RBuiltinNode {
         this.op = factory.createOperation();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    protected static Casts createCasts(Class<? extends PMinMax> extCls) {
+        Casts casts = new Casts(extCls);
         casts.arg("na.rm").defaultError(SHOW_CALLER, Message.INVALID_VALUE, "na.rm").mustBe(numericValue()).asLogicalVector().findFirst().mustBe(logicalNA().not()).map(toBoolean());
+        return casts;
     }
 
     private byte handleString(Object[] argValues, boolean naRm, int offset, int ind, int maxLength, byte warning, Object data) {
@@ -346,6 +346,11 @@ public abstract class PMinMax extends RBuiltinNode {
             super(new ReduceSemantics(RRuntime.INT_MIN_VALUE, Double.NEGATIVE_INFINITY, false, RError.Message.NO_NONMISSING_MAX, RError.Message.NO_NONMISSING_MAX_NA, false, true),
                             BinaryArithmetic.MAX);
         }
+
+        static {
+            createCasts(PMax.class);
+        }
+
     }
 
     @RBuiltin(name = "pmin", kind = INTERNAL, parameterNames = {"na.rm", "..."}, behavior = PURE)
@@ -355,6 +360,11 @@ public abstract class PMinMax extends RBuiltinNode {
             super(new ReduceSemantics(RRuntime.INT_MAX_VALUE, Double.POSITIVE_INFINITY, false, RError.Message.NO_NONMISSING_MIN, RError.Message.NO_NONMISSING_MIN_NA, false, true),
                             BinaryArithmetic.MIN);
         }
+
+        static {
+            createCasts(PMin.class);
+        }
+
     }
 
     protected boolean isIntegerPrecedence(RArgsValuesAndNames args) {
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 4a39e005809dc00097c988d13570251dee949e7a..7d68d79d72c62b7324e6ea0b4dacfce6f3a08f96 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
@@ -36,7 +36,6 @@ 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;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
@@ -101,12 +100,12 @@ public abstract class Parse extends RBuiltinNode {
     @Child private SetFixedAttributeNode setWholeSrcRefAttrNode = SetFixedAttributeNode.create("wholeSrcref");
     @Child private SetFixedAttributeNode setSrcFileAttrNode = SetFixedAttributeNode.create("srcfile");
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Parse.class);
         // Note: string is captured by the R wrapper and transformed to a file, other types not
         casts.arg("conn").defaultError(MUST_BE_STRING_OR_CONNECTION, "file").mustNotBeNull().asIntegerVector().findFirst();
         casts.arg("n").asIntegerVector().findFirst(RRuntime.INT_NA).notNA(-1);
-        casts.arg("text").allowNull().asStringVector();
+        casts.arg("text").asStringVector();
         casts.arg("prompt").asStringVector().findFirst("?");
         casts.arg("encoding").mustBe(stringValue()).asStringVector().findFirst();
     }
@@ -174,7 +173,8 @@ public abstract class Parse extends RBuiltinNode {
     private static Source createSource(Object srcFile, String coalescedLines) {
         if (srcFile instanceof REnvironment) {
             REnvironment srcFileEnv = (REnvironment) srcFile;
-            boolean isFile = RRuntime.fromLogical((byte) srcFileEnv.get("isFile"));
+            Object b = srcFileEnv.get("isFile");
+            boolean isFile = RRuntime.fromLogical(b != null ? (byte) b : 0);
             if (isFile) {
                 // Might be a URL
                 String urlFileName = RRuntime.asString(srcFileEnv.get("filename"));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
index cdb0a92d5d643a58da3ac301a17377e81323104e..9b682fe956c9924aa7e155f2cbf9a2cbda9e30a2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,20 +22,27 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyStringVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
+import static com.oracle.truffle.r.runtime.RError.Message.NON_STRING_ARG_TO_INTERNAL_PASTE;
+import static com.oracle.truffle.r.runtime.RError.SHOW_CALLER;
 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.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
 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.nodes.function.ClassHierarchyNode;
+import com.oracle.truffle.r.nodes.function.call.RExplicitBaseEnvCallDispatcher;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -43,57 +50,62 @@ 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.model.RAbstractListVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "paste", kind = INTERNAL, parameterNames = {"", "sep", "collapse"}, behavior = PURE)
 public abstract class Paste extends RBuiltinNode {
 
     private static final String[] ONE_EMPTY_STRING = new String[]{""};
 
-    public abstract Object executeList(RList value, String sep, Object collapse);
+    public abstract Object executeList(VirtualFrame frame, RList value, String sep, Object collapse);
 
-    /**
-     * {@code paste} is specified to convert its arguments using {@code as.character}.
-     */
-    @Child private AsCharacter asCharacterNode;
-    @Child private CastStringNode castCharacterNode;
+    @Child private ClassHierarchyNode classHierarchyNode;
+    @Child private CastNode asCharacterNode;
+    @Child private CastNode castAsCharacterResultNode;
+    @Child private RExplicitBaseEnvCallDispatcher asCharacterDispatcher;
+    @Child private BoxPrimitiveNode boxPrimitiveNode = BoxPrimitiveNode.create();
 
     private final ValueProfile lengthProfile = PrimitiveValueProfile.createEqualityProfile();
     private final ConditionProfile reusedResultProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile nonNullElementsProfile = BranchProfile.create();
     private final BranchProfile onlyNullElementsProfile = BranchProfile.create();
+    private final ConditionProfile isNotStringProfile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile hasNoClassProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Paste.class);
         casts.arg(0).mustBe(RAbstractListVector.class);
         casts.arg("sep").asStringVector().findFirst(Message.INVALID_SEPARATOR);
         casts.arg("collapse").allowNull().mustBe(stringValue()).asStringVector().findFirst();
     }
 
-    /**
-     * FIXME The exact semantics needs checking regarding the use of {@code as.character}. Currently
-     * there are problem using it here, so we retain the previous implementation that just uses
-     * {@link CastStringNode}.
-     */
-    private RStringVector castCharacterVector(Object o) {
-        if (castCharacterNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            castCharacterNode = insert(CastStringNodeGen.create(false, false, false));
+    private RAbstractStringVector castCharacterVector(VirtualFrame frame, Object o) {
+        // Note: GnuR does not actually invoke as.character for character values, even if they have
+        // class and uses their value directly
+        Object result = o;
+        if (isNotStringProfile.profile(!(o instanceof String || o instanceof RAbstractStringVector))) {
+            result = castNonStringToCharacterVector(frame, result);
         }
-        Object ret = castCharacterNode.executeString(o);
-        if (ret instanceof String) {
-            return RDataFactory.createStringVector((String) ret);
-        } else if (ret == RNull.instance) {
-            return RDataFactory.createEmptyStringVector();
-        } else {
-            return (RStringVector) ((RStringVector) ret).copyDropAttributes();
+        // box String to RAbstractStringVector
+        return (RAbstractStringVector) boxPrimitiveNode.execute(result);
+    }
+
+    private Object castNonStringToCharacterVector(VirtualFrame frame, Object result) {
+        RStringVector classVec = getClassHierarchyNode().execute(result);
+        if (hasNoClassProfile.profile(classVec == null || classVec.getLength() == 0)) {
+            // coerce non-string result to string, i.e. do what 'as.character' would do
+            return getAsCharacterNode().execute(result);
         }
+        // invoke the actual 'as.character' function (with its dispatch)
+        ensureAsCharacterFuncNodes();
+        return castAsCharacterResultNode.execute(asCharacterDispatcher.call(frame, result));
     }
 
     @Specialization
-    protected RStringVector pasteList(RAbstractListVector values, String sep, @SuppressWarnings("unused") RNull collapse) {
+    protected RStringVector pasteListNullSep(VirtualFrame frame, RAbstractListVector values, String sep, @SuppressWarnings("unused") RNull collapse) {
         int length = lengthProfile.profile(values.getLength());
         if (hasNonNullElements(values, length)) {
-            String[] result = pasteListElements(values, sep, length);
+            String[] result = pasteListElements(frame, values, sep, length);
             return RDataFactory.createStringVector(result, RDataFactory.COMPLETE_VECTOR);
         } else {
             return RDataFactory.createEmptyStringVector();
@@ -101,10 +113,10 @@ public abstract class Paste extends RBuiltinNode {
     }
 
     @Specialization
-    protected String pasteList(RAbstractListVector values, String sep, String collapse) {
+    protected String pasteList(VirtualFrame frame, RAbstractListVector values, String sep, String collapse) {
         int length = lengthProfile.profile(values.getLength());
         if (hasNonNullElements(values, length)) {
-            String[] result = pasteListElements(values, sep, length);
+            String[] result = pasteListElements(frame, values, sep, length);
             return collapseString(result, collapse);
         } else {
             return "";
@@ -122,12 +134,12 @@ public abstract class Paste extends RBuiltinNode {
         return false;
     }
 
-    private String[] pasteListElements(RAbstractListVector values, String sep, int length) {
+    private String[] pasteListElements(VirtualFrame frame, RAbstractListVector values, String sep, int length) {
         String[][] converted = new String[length][];
         int maxLength = 1;
         for (int i = 0; i < length; i++) {
             Object element = values.getDataAt(i);
-            String[] array = castCharacterVector(element).getDataWithoutCopying();
+            String[] array = castCharacterVector(frame, element).materialize().getDataWithoutCopying();
             maxLength = Math.max(maxLength, array.length);
             converted[i] = array.length == 0 ? ONE_EMPTY_STRING : array;
         }
@@ -203,4 +215,31 @@ public abstract class Paste extends RBuiltinNode {
         assert pos == stringLength;
         return new String(chars);
     }
+
+    private void ensureAsCharacterFuncNodes() {
+        if (asCharacterDispatcher == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            asCharacterDispatcher = insert(RExplicitBaseEnvCallDispatcher.create("as.character"));
+        }
+        if (castAsCharacterResultNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            castAsCharacterResultNode = insert(newCastBuilder().mustBe(stringValue(), SHOW_CALLER, NON_STRING_ARG_TO_INTERNAL_PASTE).buildCastNode());
+        }
+    }
+
+    private ClassHierarchyNode getClassHierarchyNode() {
+        if (classHierarchyNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            classHierarchyNode = insert(ClassHierarchyNode.create());
+        }
+        return classHierarchyNode;
+    }
+
+    private CastNode getAsCharacterNode() {
+        if (asCharacterNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            asCharacterNode = insert(newCastBuilder().returnIf(nullValue(), emptyStringVector()).asStringVector().buildCastNode());
+        }
+        return asCharacterNode;
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java
index 1cf530d6512758af6d9f038d83876c5c6d9ecc25..c00334447c68e3f0ddf4fd9a95687a6fa26a7c91 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste0.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@ 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.api.frame.VirtualFrame;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -41,14 +41,14 @@ public abstract class Paste0 extends RBuiltinNode {
 
     @Child private Paste pasteNode = PasteNodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Paste0.class);
         casts.arg("list").mustBe(RList.class);
         casts.arg("collapse").allowNull().mustBe(stringValue()).asStringVector().findFirst();
     }
 
     @Specialization
-    protected Object paste0(RList values, Object collapse) {
-        return pasteNode.executeList(values, "", collapse);
+    protected Object paste0(VirtualFrame frame, RList values, Object collapse) {
+        return pasteNode.executeList(frame, values, "", collapse);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java
index 640b323010095b81810560ba398ca39a4b9028ea..fe07eed30f65a47f88c8d9eb8c39e3d4ced3f71c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PathExpand.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -38,8 +37,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "path.expand", kind = INTERNAL, parameterNames = "path", behavior = IO)
 public abstract class PathExpand extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(PathExpand.class);
         casts.arg("path").mustBe(stringValue());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java
index b1881322b5ec87bb91d8bdbf810a45cc9442b1bb..aa7eaefcc74362e768a04c08765ff762f4df2445 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Pretty.java
@@ -21,7 +21,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -36,8 +35,8 @@ public abstract class Pretty extends RBuiltinNode {
 
     private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"l", "u", "n"}, RDataFactory.COMPLETE_VECTOR);
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Pretty.class);
         casts.arg("l").asDoubleVector().findFirst().mustBe(isFinite());
         casts.arg("u").asDoubleVector().findFirst().mustBe(isFinite());
         casts.arg("n").asIntegerVector().findFirst().notNA().mustBe(gte0());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java
index fdcad6132cc24b5119b071873ca097ca83765435..0a6d792c11e56c01789697c7799bcb810f7efee4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@ 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.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;
@@ -45,8 +44,8 @@ public abstract class Primitive extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Primitive.class);
         casts.arg("name").defaultError(Message.STRING_ARGUMENT_REQUIRED).mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
     }
 
@@ -57,7 +56,7 @@ public abstract class Primitive extends RBuiltinNode {
         return function;
     }
 
-    @Specialization(contains = "primitiveCached")
+    @Specialization(replaces = "primitiveCached")
     protected RFunction primitive(String name) {
         RFunction function = lookup(name);
         return function;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
index 4e4786a07b180c8a30a8e3296b88cd642866b3df..9abaf902ac3f6f2f215952fbd29178e06c95035c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.printer.PrintParameters;
 import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinterNode;
@@ -60,8 +59,8 @@ public class PrintFunctions {
 
         @Child private ValuePrinterNode valuePrinter = new ValuePrinterNode();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PrintDefault.class);
             casts.arg("digits").allowNull().asIntegerVector().findFirst().mustBe(notIntNA()).mustBe(gte(Format.R_MIN_DIGITS_OPT).and(lte(Format.R_MAX_DIGITS_OPT)));
 
             casts.arg("quote").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -80,8 +79,8 @@ public class PrintFunctions {
         }
 
         @Specialization(guards = "!isS4(o)")
-        protected Object printDefault(VirtualFrame frame, Object o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt) {
-            valuePrinter.execute(frame, o, digits, quote, naPrint, printGap, right, max, useSource, noOpt);
+        protected Object printDefault(Object o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt) {
+            valuePrinter.execute(o, digits, quote, naPrint, printGap, right, max, useSource, noOpt);
             return o;
         }
 
@@ -90,13 +89,14 @@ public class PrintFunctions {
         }
 
         @Specialization(guards = "isS4(o)")
-        protected Object printDefaultS4(VirtualFrame frame, RTypedValue o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt,
+        protected Object printDefaultS4(@SuppressWarnings("unused") VirtualFrame frame, RTypedValue o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max,
+                        boolean useSource, boolean noOpt,
                         @Cached("createShowFunction(frame)") RFunction showFunction) {
             if (noOpt) {
                 // S4 should only be called in case noOpt is true
                 RContext.getEngine().evalFunction(showFunction, null, null, null, o);
             } else {
-                printDefault(frame, showFunction, digits, quote, naPrint, printGap, right, max, useSource, noOpt);
+                printDefault(showFunction, digits, quote, naPrint, printGap, right, max, useSource, noOpt);
             }
             return o;
         }
@@ -111,17 +111,16 @@ public class PrintFunctions {
 
         @Child private ValuePrinterNode valuePrinter = new ValuePrinterNode();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PrintFunction.class);
             casts.arg("x").mustBe(instanceOf(RFunction.class));
 
             casts.arg("useSource").defaultError(RError.Message.INVALID_ARGUMENT, "useSource").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
         }
 
-        @SuppressWarnings("unused")
         @Specialization
-        protected RFunction printFunction(VirtualFrame frame, RFunction x, boolean useSource, RArgsValuesAndNames extra) {
-            valuePrinter.execute(frame, x, PrintParameters.getDefaultDigits(), true, RString.valueOf(RRuntime.STRING_NA), 1, false, PrintParameters.getDefaultMaxPrint(), useSource, false);
+        protected RFunction printFunction(RFunction x, boolean useSource, @SuppressWarnings("unused") RArgsValuesAndNames extra) {
+            valuePrinter.execute(x, PrintParameters.getDefaultDigits(), true, RString.valueOf(RRuntime.STRING_NA), 1, false, PrintParameters.getDefaultMaxPrint(), useSource, false);
             return x;
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
index 8c3caafcc5fd2c0f40e07d253411d6b734cde53d..132a9648895544e951e370763858a77e5063bd4a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -32,6 +32,10 @@ public abstract class Prod extends RBuiltinNode {
 
     // TODO: handle multiple arguments, handle na.rm
 
+    static {
+        Casts.noCasts(Prod.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE};
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java
index 70ecc15e2ab29957db60aa4ba1c8cbb26e36ef38..37bba1bf203b24d61c73dd5690a30c34f7cd44d6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quantifier.java
@@ -28,6 +28,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
+import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
@@ -35,8 +36,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-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.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -78,16 +77,19 @@ public abstract class Quantifier extends RBuiltinNode {
         return new Object[]{RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    protected static Casts createCasts(Class<? extends Quantifier> extCls) {
+        Casts casts = new Casts(extCls);
         casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
+        return casts;
     }
 
     private void createArgCast(int index) {
-        CastBuilder argCastBuilder = new CastBuilder();
-        argCastBuilder.arg(0).allowNull().shouldBe(integerValue().or(logicalValue()).or(instanceOf(RAbstractVector.class).and(size(0))), RError.Message.COERCING_ARGUMENT, typeName(),
-                        "logical").asLogicalVector();
-        argCastNodes[index] = insert(new ProfileCastNode(argCastBuilder.getCasts()[0]));
+        // @formatter:off
+        argCastNodes[index] = insert(new ProfileCastNode(newCastBuilder().allowNull().
+            shouldBe(integerValue().or(logicalValue()).or(instanceOf(RAbstractVector.class).and(size(0))),
+                    RError.Message.COERCING_ARGUMENT, typeName(), "logical").
+            asLogicalVector().buildCastNode()));
+        // @formatter:on
     }
 
     protected boolean emptyVectorResult() {
@@ -123,7 +125,7 @@ public abstract class Quantifier extends RBuiltinNode {
         return result;
     }
 
-    @Specialization(contains = "opCachedLength")
+    @Specialization(replaces = "opCachedLength")
     protected byte op(RArgsValuesAndNames args, boolean naRm) {
         boolean profiledNaRm = naRm;
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
index 30d73cb3be9603add4e504a2591c80907bbbffdc..4a3d93122cab344c22ab3bff41cd344f2787faa5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java
@@ -19,7 +19,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RCleanUp;
 import com.oracle.truffle.r.runtime.RError;
@@ -34,8 +33,8 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "quit", visibility = OFF, kind = INTERNAL, parameterNames = {"save", "status", "runLast"}, behavior = COMPLEX)
 public abstract class Quit extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Quit.class);
         casts.arg("save").mustBe(stringValue(), RError.Message.QUIT_ASK).asStringVector().findFirst();
         casts.arg("status").asIntegerVector().findFirst();
         casts.arg("runLast").asLogicalVector().findFirst();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
index f3d805fcebb1295617aaf6fd4b0fb5e0715c9339..98620c384f3b17e826ea6058afa2a3c7ace3a036 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,10 @@ public abstract class Quote extends RBuiltinNode {
 
     protected static final int LIMIT = 3;
 
+    static {
+        Casts.noCasts(Quote.class);
+    }
+
     private final ConditionProfile shareableProfile = ConditionProfile.createBinaryProfile();
 
     public abstract Object execute(RPromise expr);
@@ -68,7 +72,7 @@ public abstract class Quote extends RBuiltinNode {
         return language;
     }
 
-    @Specialization(contains = "quoteCached")
+    @Specialization(replaces = "quoteCached")
     protected Object quote(RPromise expr) {
         return createLanguage(expr.getClosure());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
index 56eb613f4988953f0121e14a1349a012cc241d50..315f03279d911c82020ff0608d5c320dbc28f618 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RNGFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -52,10 +52,10 @@ public class RNGFunctions {
     @RBuiltin(name = "set.seed", visibility = OFF, kind = INTERNAL, parameterNames = {"seed", "kind", "normal.kind"}, behavior = MODIFIES_STATE)
     public abstract static class SetSeed extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SetSeed.class);
             casts.arg("seed").allowNull().mustBe(numericValue(), SHOW_CALLER, SEED_NOT_VALID_INT).asIntegerVector().findFirst();
-            Casts.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
+            CastsHelper.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
             // TODO: implement normal.kind specializations with String
             casts.arg("normal.kind").allowNull().mustBe(anyValue().not(), UNIMPLEMENTED_TYPE_IN_FUNCTION, "String", "set.seed").mustBe(stringValue(), SHOW_CALLER, INVALID_NORMAL_TYPE_IN_RGNKIND);
         }
@@ -83,10 +83,10 @@ public class RNGFunctions {
     @RBuiltin(name = "RNGkind", kind = INTERNAL, parameterNames = {"kind", "normkind"}, behavior = MODIFIES_STATE)
     public abstract static class RNGkind extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
-            Casts.kindInteger(casts, "normkind", INVALID_NORMAL_TYPE_IN_RGNKIND);
+        static {
+            Casts casts = new Casts(RNGkind.class);
+            CastsHelper.kindInteger(casts, "kind", INVALID_ARGUMENT, "kind");
+            CastsHelper.kindInteger(casts, "normkind", INVALID_NORMAL_TYPE_IN_RGNKIND);
         }
 
         @Specialization
@@ -102,8 +102,8 @@ public class RNGFunctions {
         }
     }
 
-    private static final class Casts {
-        public static void kindInteger(CastBuilder casts, String name, Message error, Object... messageArgs) {
+    private static final class CastsHelper {
+        public static void kindInteger(Casts casts, String name, Message error, Object... messageArgs) {
             casts.arg(name).mapNull(constant(RRNG.NO_KIND_CHANGE)).mustBe(numericValue(), SHOW_CALLER, error, messageArgs).asIntegerVector().findFirst();
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
index 1fc6d58be8307d0d84c261b89ca335991ebf43f5..72ab6ad5c7e4227fd90998c13f5f7ed3825a0e0f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java
@@ -29,7 +29,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode.ReduceSemantics;
@@ -53,8 +52,8 @@ public abstract class Range extends RBuiltinNode {
     @Child private UnaryArithmeticReduceNode minReduce = UnaryArithmeticReduceNodeGen.create(minSemantics, BinaryArithmetic.MIN);
     @Child private UnaryArithmeticReduceNode maxReduce = UnaryArithmeticReduceNodeGen.create(maxSemantics, BinaryArithmetic.MAX);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Range.class);
         casts.arg("na.rm").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("finite").asLogicalVector().findFirst().map(toBoolean());
     }
@@ -79,7 +78,7 @@ public abstract class Range extends RBuiltinNode {
         }
     }
 
-    @Specialization(contains = "rangeLengthOne")
+    @Specialization(replaces = "rangeLengthOne")
     protected RVector<?> range(RArgsValuesAndNames args, boolean naRm, boolean finite,
                     @Cached("create()") Combine combine) {
         Object combined = combine.executeCombine(args, false);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java
index 73efc9004d81b14deb28319850e3ad5705e8628a..16f4d02288df99cd558c9ce7b8f13234589980ba 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rank.java
@@ -34,7 +34,6 @@ import java.util.function.Function;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.CmpNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.OrderNodeGen.OrderVector1NodeGen;
@@ -62,20 +61,17 @@ public abstract class Rank extends RBuiltinNode {
         MIN
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
+    static {
+        Casts casts = new Casts(Rank.class);
         Function<Object, Object> typeFunc = x -> x.getClass().getSimpleName();
         casts.arg("x").mustBe(abstractVectorValue(), SHOW_CALLER, UNIMPLEMENTED_TYPE_IN_GREATER, typeFunc).mustBe(not(rawValue()), SHOW_CALLER, RError.Message.RAW_SORT);
-        // Note: in the case of no long vector support, when given anything but integer as n, GnuR behaves as if n=1,
+        // Note: in the case of no long vector support, when given anything but integer as n, GnuR
+        // behaves as if n=1,
         // we allow ourselves to be bit inconsistent with GnuR in that.
-        casts.arg("len").defaultError(NO_CALLER, INVALID_VALUE, "length(xx)").mustBe(numericValue()).
-                asIntegerVector().
-                mustBe(notEmpty()).
-                findFirst().mustBe(intNA().not().and(gte0()));
-        // Note: we parse ties.methods in the Specialization anyway, so the validation of the value is there
+        casts.arg("len").defaultError(NO_CALLER, INVALID_VALUE, "length(xx)").mustBe(numericValue()).asIntegerVector().mustBe(notEmpty()).findFirst().mustBe(intNA().not().and(gte0()));
+        // Note: we parse ties.methods in the Specialization anyway, so the validation of the value
+        // is there
         casts.arg("ties.method").defaultError(NO_CALLER, INVALID_TIES_FOR_RANK).mustBe(stringValue()).asStringVector().findFirst();
-        // @formatter:on
     }
 
     private Order.OrderVector1Node initOrderVector1() {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
index 3a5414d396c6ffa846dda211718eecbe2a92ac36..4278530d54041bc9d62b0e24d0dbe9e542fcd48b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java
@@ -35,7 +35,6 @@ 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.ConditionProfile;
-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.builtins.RBuiltin;
@@ -53,8 +52,8 @@ public class RawFunctions {
     @RBuiltin(name = "charToRaw", kind = INTERNAL, parameterNames = "x", behavior = PURE)
     public abstract static class CharToRaw extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(CharToRaw.class);
             casts.arg("x").defaultError(RError.Message.ARG_MUST_BE_CHARACTER_VECTOR_LENGTH_ONE).mustBe(stringValue()).asStringVector().mustBe(notEmpty());
         }
 
@@ -74,8 +73,9 @@ public class RawFunctions {
 
     @RBuiltin(name = "rawToChar", kind = INTERNAL, parameterNames = {"x", "multiple"}, behavior = PURE)
     public abstract static class RawToChar extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(RawToChar.class);
             casts.arg("x").mustBe(instanceOf(RAbstractRawVector.class), RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x");
             casts.arg("multiple").defaultError(RError.Message.INVALID_LOGICAL).asLogicalVector().findFirst().notNA().map(toBoolean());
         }
@@ -107,8 +107,9 @@ public class RawFunctions {
 
     @RBuiltin(name = "rawShift", kind = INTERNAL, parameterNames = {"x", "n"}, behavior = PURE)
     public abstract static class RawShift extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(RawShift.class);
             casts.arg("x").mustBe(instanceOf(RAbstractRawVector.class), RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x");
             casts.arg("n").defaultError(RError.Message.MUST_BE_SMALL_INT, "shift").asIntegerVector().findFirst().notNA().mustBe(gte(-8).and(lte(8)));
         }
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
index ec205c198a4bf9870dc143127a22bf4188ece51a..538a0d8c685b99f55f14cc98478b740dfb422e7e 100644
--- 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@ 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;
@@ -37,8 +36,8 @@ 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) {
+    static {
+        Casts casts = new Casts(RawToBits.class);
         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");
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java
index f5723074288a2a5e1d6c23fe82a544559bf575e4..f0a6a895958d889f1a046f5a434d4b2354de71d0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java
@@ -35,7 +35,6 @@ import java.util.Set;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.DCF;
 import com.oracle.truffle.r.runtime.RError;
@@ -52,8 +51,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "readDCF", kind = INTERNAL, parameterNames = {"conn", "fields", "keepwhite"}, behavior = IO)
 public abstract class ReadDCF extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ReadDCF.class);
         casts.arg("conn").defaultError(Message.INVALID_CONNECTION).asIntegerVector().findFirst();
         casts.arg("fields").mapNull(emptyStringVector()).asStringVector();
         casts.arg("keepwhite").mapNull(emptyStringVector()).asStringVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java
index 4ee6dbbd2502a83640dfc8e70d59f4419f199da8..999f8ef7f3d99c854995c2714c0abe3a884d1d41 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadREnviron.java
@@ -32,7 +32,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.context.RContext;
 @RBuiltin(name = "readRenviron", visibility = OFF, kind = INTERNAL, parameterNames = "x", behavior = COMPLEX)
 public abstract class ReadREnviron extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ReadREnviron.class);
         casts.arg("x").mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_STRING, "x").asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java
index 41f4eb9edbf28b16507ff62062abc6b9f5758287..bc5411859c8e3aff340dd5a79000ae01c4e690ff 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Readline.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.context.ConsoleHandler;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "readline", kind = INTERNAL, parameterNames = "prompt", behavior = IO)
 public abstract class Readline extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Readline.class);
         casts.arg("prompt").asStringVector().findFirst("");
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java
index c3ea2d467ac13740518b397f3f789c3452ca1b26..4c53575646846ef0baac6dcc1e11b3bb3532cc2a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Recall.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,11 +30,10 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.access.FrameSlotNode;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.GetCallerFrameNode;
-import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RError;
@@ -54,9 +53,11 @@ public abstract class Recall extends RBuiltinNode {
 
     @Child private GetCallerFrameNode callerFrame = new GetCallerFrameNode();
 
-    private final Object argsIdentifier = new Object();
-    @Child private RCallNode call = RCallNode.createExplicitCall(argsIdentifier);
-    @Child private FrameSlotNode slot = FrameSlotNode.createTemp(argsIdentifier, true);
+    @Child private RExplicitCallNode call = RExplicitCallNode.create();
+
+    static {
+        Casts.noCasts(Recall.class);
+    }
 
     @Specialization
     protected Object recall(VirtualFrame frame, @SuppressWarnings("unused") RArgsValuesAndNames args) {
@@ -71,7 +72,6 @@ public abstract class Recall extends RBuiltinNode {
          * builtin looks at the arguments passed to the surrounding function.
          */
         RArgsValuesAndNames actualArgs = (RArgsValuesAndNames) readArgs.execute(frame);
-        frame.setObject(slot.executeFrameSlot(frame), actualArgs);
-        return call.execute(frame, function);
+        return call.execute(frame, function, actualArgs);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RecordGraphics.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RecordGraphics.java
index b0be4bf5342b864edfc78816e3218bb41c1494fb..5182327ab41aeac25c16cefd9204729f11e4dc36 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RecordGraphics.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RecordGraphics.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -53,6 +54,13 @@ public abstract class RecordGraphics extends RBuiltinNode {
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
     @Child private RList2EnvNode list2EnvNode = new RList2EnvNode();
 
+    static {
+        Casts casts = new Casts(RecordGraphics.class);
+        casts.arg("expr").mustBe(instanceOf(RLanguage.class).or(instanceOf(RExpression.class)));
+        casts.arg("list").mustBe(instanceOf(RList.class));
+        casts.arg("env").mustBe(instanceOf(REnvironment.class));
+    }
+
     public static RecordGraphics create() {
         return RecordGraphicsNodeGen.create();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java
index 079bd5fdcb2ea7fe4e1b73189f411c788b47d8c7..4703cc2b232534e3199c5fd0d657f590ed8220e0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RegFinalizer.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -39,8 +38,9 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "reg.finalizer", kind = INTERNAL, parameterNames = {"e", "f", "onexit"}, behavior = COMPLEX)
 public abstract class RegFinalizer extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(RegFinalizer.class);
         casts.arg("e").mustBe(instanceOf(REnvironment.class).or(instanceOf(RExternalPtr.class)), RError.Message.REG_FINALIZER_FIRST);
         casts.arg("f").mustBe(instanceOf(RFunction.class), RError.Message.REG_FINALIZER_SECOND);
         casts.arg("onexit").asLogicalVector().findFirst().notNA(RError.Message.REG_FINALIZER_THIRD).map(toBoolean());
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 e89c2645f46e5482347b24152fbff85318ef7c3a..5d1bd20567546186b848131e658d4c926d1c73c7 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,12 +26,12 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVect
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.intNA;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 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 java.util.Arrays;
-import java.util.function.Function;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -40,7 +40,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 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;
@@ -48,7 +47,6 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
 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.RAbstractIntVector;
@@ -90,14 +88,9 @@ public abstract class Repeat extends RBuiltinNode {
         return new Object[]{RMissing.instance, 1, RRuntime.INT_NA, 1};
     }
 
-    private String argType(Object arg) {
-        return ((RTypedValue) arg).getRType().getName();
-    }
-
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        Function<Object, Object> argType = this::argType;
-        casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, argType);
+    static {
+        Casts casts = new Casts(Repeat.class);
+        casts.arg("x").mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE, typeName());
         casts.arg("times").defaultError(RError.Message.INVALID_ARGUMENT, "times").mustNotBeNull().asIntegerVector();
         casts.arg("length.out").mustNotBeNull().asIntegerVector().shouldBe(size(1).or(size(0)), RError.Message.FIRST_ELEMENT_USED, "length.out").findFirst(RRuntime.INT_NA,
                         RError.Message.FIRST_ELEMENT_USED, "length.out").mustBe(intNA().or(gte(0)));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
index 5b8a41d269027f4b4408107f8a7f2fb47220de61..f376567eced2d4c06962cddf51c185e8bfc5813b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java
@@ -24,16 +24,15 @@ package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import java.util.function.Function;
 import java.util.function.IntFunction;
 
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -44,7 +43,6 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
 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;
@@ -58,14 +56,9 @@ public abstract class RepeatInternal extends RBuiltinNode {
     private final ConditionProfile timesOneProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    private String argType(Object arg) {
-        return ((RTypedValue) arg).getRType().getName();
-    }
-
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        Function<Object, Object> argType = this::argType;
-        casts.arg("x").mustBe(abstractVectorValue(), RError.SHOW_CALLER2, RError.Message.ATTEMPT_TO_REPLICATE, argType);
+    static {
+        Casts casts = new Casts(RepeatInternal.class);
+        casts.arg("x").mustBe(abstractVectorValue(), RError.SHOW_CALLER2, RError.Message.ATTEMPT_TO_REPLICATE, typeName());
         casts.arg("times").defaultError(RError.SHOW_CALLER, RError.Message.INCORRECT_ARG_TYPE, "second").mustBe(abstractVectorValue()).asIntegerVector().mustBe(notEmpty(),
                         RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "times");
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
index 90886c168a12f65bf7daf7f2f143ac7ebde0c846..163552a82d386614439cc55202e6a534b3c5dabb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -20,7 +20,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import java.util.Arrays;
 
 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.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "rep_len", kind = INTERNAL, parameterNames = {"x", "length.out"}, behavior = PURE)
 public abstract class RepeatLength extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(RepeatLength.class);
         casts.arg("x").mustBe(abstractVectorValue(), RError.SHOW_CALLER, RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR);
         // with default error message, SHOW_CALLER does not work
         casts.arg("length.out").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(size(1)).findFirst().mustBe(notIntNA());
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 d2407dfe625f4cda14649e91c61417c594371646..e990562976c17c4c4e23cf86f72bdc64776dde0d 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,16 +25,39 @@ 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.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.nodes.function.FunctionDefinitionNode;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 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.RList;
+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.nodes.RNode;
+
+final class ReturnSpecial extends RNode {
+
+    @Child private RNode value;
+    private final BranchProfile isPromiseEvalProfile = BranchProfile.create();
+
+    protected ReturnSpecial(RNode value) {
+        this.value = value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return Return.doReturn(frame, value.visibleExecute(frame), isPromiseEvalProfile);
+    }
+}
 
 /**
  * Return a value from the currently executing function, which is identified by the
@@ -42,18 +65,23 @@ import com.oracle.truffle.r.runtime.data.RNull;
  * delivered via a {@link ReturnException}, which is subsequently caught in the
  * {@link FunctionDefinitionNode}.
  */
-@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
+@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX, nonEvalArgs = {0})
 public abstract class Return extends RBuiltinNode {
 
-    private final BranchProfile isPromiseEvalProfile = BranchProfile.create();
+    public static RNode createSpecial(@SuppressWarnings("unused") ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) {
+        return arguments.length == 1 ? new ReturnSpecial(arguments[0]) : null;
+    }
+
+    static {
+        Casts.noCasts(Return.class);
+    }
 
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RNull.instance};
     }
 
-    @Specialization
-    protected Object returnFunction(VirtualFrame frame, Object value) {
+    static ReturnException doReturn(VirtualFrame frame, Object value, BranchProfile isPromiseEvalProfile) {
         RCaller call = RArguments.getCall(frame);
         while (call.isPromise()) {
             isPromiseEvalProfile.enter();
@@ -61,4 +89,22 @@ public abstract class Return extends RBuiltinNode {
         }
         throw new ReturnException(value, call);
     }
+
+    @Specialization
+    protected Object returnFunction(VirtualFrame frame, RPromise x,
+                    @Cached("new()") PromiseHelperNode promiseHelper,
+                    @Cached("create()") BranchProfile isPromiseEvalProfile,
+                    @Cached("create()") SetVisibilityNode visibility) {
+        if (x.isEvaluated()) {
+            visibility.execute(frame, true);
+        }
+        Object value = promiseHelper.evaluate(frame, x);
+        throw doReturn(frame, value, isPromiseEvalProfile);
+    }
+
+    @Specialization
+    protected RList returnFunction(VirtualFrame frame, @SuppressWarnings("unused") RMissing x,
+                    @Cached("create()") BranchProfile isPromiseEvalProfile) {
+        throw doReturn(frame, RNull.instance, isPromiseEvalProfile);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java
index 74eb30e05f18afe578d50382ab41fa390c7b1e91..544075d500a238cd222f6e3253fde3f2e613aa73 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,6 @@ import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RError;
@@ -59,8 +58,8 @@ public abstract class Rm extends RBuiltinNode {
 
     private final BranchProfile invalidateProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Rm.class);
         casts.arg("list").mustBe(stringValue(), SHOW_CALLER, INVALID_FIRST_ARGUMENT);
         casts.arg("envir").mustNotBeNull(SHOW_CALLER, USE_NULL_ENV_DEFUNCT).mustBe(REnvironment.class, SHOW_CALLER, INVALID_ARGUMENT, "envir");
         casts.arg("inherits").mustBe(numericValue(), SHOW_CALLER, INVALID_ARGUMENT, "inherits").asLogicalVector().findFirst().map(toBoolean());
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 9c23cbd7326bf0ac9ef7347641b3dee044c30def..13230809bec5a91311616381d6ef0776ef5aebfa 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
@@ -30,7 +30,6 @@ 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.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;
@@ -63,24 +62,13 @@ public abstract class Round extends RBuiltinNode {
         return new Object[]{RMissing.instance, 0};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(numericValue().or(complexValue()));
+    static {
+        Casts casts = new Casts(Round.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue()));
 
         // TODO: this should also accept vectors
         // TODO: digits argument is rounded, not simply stripped off the decimal part
-        casts.arg("digits").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(numericValue().or(complexValue())).
-            asIntegerVector().
-            findFirst();
-
-        //@formatter:on
+        casts.arg("digits").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue())).asIntegerVector().findFirst();
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java
index a24d5c11c2b0f209ac0ac614e69a5dd7f6f9a3ee..245edd7529a5d4e4ac7ee9eeb94e509599404dce 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -19,7 +19,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -30,8 +29,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "row", kind = INTERNAL, parameterNames = {"dims"}, behavior = PURE)
 public abstract class Row extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Row.class);
         casts.arg("dims").defaultError(SHOW_CALLER, RError.Message.MATRIX_LIKE_REQUIRED, "row").mustBe(integerValue()).asIntegerVector().mustBe(size(2));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java
index dd72109980a9ce6bc16e31f436ce7f28737f10da..b2550c98fd68c159275a784023226cc13dd70a5d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -23,6 +23,11 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 // Implements .rowMeans
 @RBuiltin(name = "rowMeans", kind = INTERNAL, parameterNames = {"X", "m", "n", "na.rm"}, behavior = PURE)
 public abstract class RowMeans extends RowSumsBase {
+
+    static {
+        createCasts(RowMeans.class);
+    }
+
     @Specialization
     protected RDoubleVector rowMeans(RAbstractDoubleVector x, int rowNum, int colNum, boolean naRm) {
         return accumulateRows(x, rowNum, colNum, naRm, RowMeans::getMean, (v, nacheck, i) -> v.getDataAt(i));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java
index 4fe2545e4c6436b4c6f9f347c7f78c672880f687..a87847664dbea4e6ea31849fb95ebf9d18267bd2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -22,6 +22,11 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 
 @RBuiltin(name = "rowSums", kind = INTERNAL, parameterNames = {"X", "m", "n", "na.rm"}, behavior = PURE)
 public abstract class RowSums extends RowSumsBase {
+
+    static {
+        createCasts(RowSums.class);
+    }
+
     @Specialization
     protected RDoubleVector rowSums(RAbstractDoubleVector x, int rowNum, int colNum, boolean naRm) {
         return accumulateRows(x, rowNum, colNum, naRm, (sum, cnt) -> sum, (v, nacheck, i) -> v.getDataAt(i));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
index 207312d8a64a1ec44f1c22307794fdccb5b51052..f476fd860de97627ffa34e21ee1fdb090a7bee96 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1997-2015,  The R Core Team
- * Copyright (c) 2016, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -24,7 +24,6 @@ import java.util.HashMap;
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -51,8 +50,8 @@ public class RowsumFunctions {
         private final ConditionProfile typeProfile = ConditionProfile.createBinaryProfile();
         private final NACheck na = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Rowsum.class);
             casts.arg("x").mustBe(integerValue().or(doubleValue()), RError.Message.ROWSUM_NON_NUMERIC);
 
             casts.arg("g").asVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java
index fe0c2dcfdeb9a00ad2a338387495faa551340ffa..76766dbfcf461522ebdfe0526af8661222a63a6e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java
@@ -101,6 +101,10 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
         private final ConditionProfile argMissingProfile = ConditionProfile.createBinaryProfile();
         private final ConditionProfile argsValueAndNamesProfile = ConditionProfile.createBinaryProfile();
 
+        static {
+            Casts.noCasts(UseMethod.class);
+        }
+
         protected UseMethod() {
             super(false);
         }
@@ -193,6 +197,10 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
         private final ValueProfile parameterSignatureProfile = ValueProfile.createIdentityProfile();
         private final ValueProfile suppliedParameterSignatureProfile = ValueProfile.createIdentityProfile();
 
+        static {
+            Casts.noCasts(NextMethod.class);
+        }
+
         protected NextMethod() {
             super(true);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java
index 682bbc28bcc7795c9afdcabc80e33ce16383d444..961dd4dfee08e12bf3c80324ee90fcd0a5b6aee1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java
@@ -7,7 +7,7 @@
  * Copyright (c) 1997-2012, The R Core Team
  * Copyright (c) 2003-2008, The R Foundation
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -39,7 +39,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -54,24 +53,15 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
 public abstract class Sample extends RBuiltinNode {
     private final ConditionProfile sampleSizeProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
-        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().
-                mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER, VECTOR_SIZE_NA_NAN).
-                mapIf(doubleValue(), chain(asDoubleVector()).with(findFirst().doubleElement()).
-                        with(mustBe(isFinite(), SHOW_CALLER, VECTOR_SIZE_NA_NAN)).
-                        with(mustBe(lt(4.5e15), SHOW_CALLER, VECTOR_SIZE_TOO_LARGE)).end()).
-                asIntegerVector().findFirst().mustBe(gte0());
-        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                mustBe(integerValue().or(doubleValue()).or(stringValue())).
-                asIntegerVector().findFirst().
-                defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                notNA().mustBe(gte0());
-        casts.arg("replace").mustBe(integerValue().or(doubleValue()).or(logicalValue())).
-                asLogicalVector().mustBe(singleElement()).findFirst().notNA().map(toBoolean());
-        casts.arg("prob").allowNull().asDoubleVector();
-        // @formatter:on
+    static {
+        Casts casts = new Casts(Sample.class);
+        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER, VECTOR_SIZE_NA_NAN).mapIf(doubleValue(),
+                        chain(asDoubleVector()).with(findFirst().doubleElement()).with(mustBe(isFinite(), SHOW_CALLER, VECTOR_SIZE_NA_NAN)).with(
+                                        mustBe(lt(4.5e15), SHOW_CALLER, VECTOR_SIZE_TOO_LARGE)).end()).asIntegerVector().findFirst().mustBe(gte0());
+        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").mustBe(integerValue().or(doubleValue()).or(stringValue())).asIntegerVector().findFirst().defaultError(SHOW_CALLER,
+                        INVALID_ARGUMENT, "size").notNA().mustBe(gte0());
+        casts.arg("replace").mustBe(integerValue().or(doubleValue()).or(logicalValue())).asLogicalVector().mustBe(singleElement()).findFirst().notNA().map(toBoolean());
+        casts.arg("prob").asDoubleVector();
     }
 
     // Validation that correlates two or more argument values (note: positiveness of prob is checked
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java
index 90fb10fe618aa91a43b4401f37b737a0aa444660..8b1ad3e4b693e339e09038e755dcb26eef53065f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample2.java
@@ -28,7 +28,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSetDouble;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSetInt;
@@ -50,18 +49,12 @@ public abstract class Sample2 extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        // @formatter:off
-        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().
-                mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER, INVALID_FIRST_ARGUMENT).
-                asDoubleVector().findFirst().mustBe(gte(0.0)).mustBe(isFinite());
-        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                mustBe(integerValue().or(doubleValue())).
-                asIntegerVector().findFirst().
-                defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").
-                notNA().mustBe(gte0());
-        // @formatter:on
+    static {
+        Casts casts = new Casts(Sample2.class);
+        casts.arg("x").defaultError(SHOW_CALLER, INVALID_FIRST_ARGUMENT).allowNull().mustBe(integerValue().or(doubleValue())).notNA(SHOW_CALLER,
+                        INVALID_FIRST_ARGUMENT).asDoubleVector().findFirst().mustBe(gte(0.0)).mustBe(isFinite());
+        casts.arg("size").defaultError(SHOW_CALLER, INVALID_ARGUMENT, "size").mustBe(integerValue().or(doubleValue())).asIntegerVector().findFirst().defaultError(SHOW_CALLER, INVALID_ARGUMENT,
+                        "size").notNA().mustBe(gte0());
     }
 
     @Specialization(guards = "x > MAX_INT")
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 86377c5a1a09d11f700faff80ddd8072a8617d71..d80ec47fd7af1df9e9f57671b3595dd49f450b64 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
@@ -32,7 +32,6 @@ 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;
@@ -101,8 +100,8 @@ public abstract class Scan extends RBuiltinNode {
         boolean skipNull = false;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Scan.class);
         casts.arg("file").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
 
         casts.arg("what").asVector();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java
index bb4e2eba824e3aee8169d3ef753bd444fdcc8633..27ec4be7937f911e99d9d12c24f4df2a544bf731 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java
@@ -12,7 +12,9 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notIntNA;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
+import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
 import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
 import static com.oracle.truffle.r.runtime.RError.NO_CALLER;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
@@ -23,15 +25,11 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
-import com.oracle.truffle.api.frame.FrameSlot;
 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.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.access.FrameSlotNode;
-import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.SeqFunctions.SeqInt.IsIntegralNumericNode;
 import com.oracle.truffle.r.nodes.builtin.base.SeqFunctionsFactory.GetIntegralNumericNodeGen;
@@ -44,11 +42,8 @@ import com.oracle.truffle.r.nodes.ffi.AsRealNode;
 import com.oracle.truffle.r.nodes.ffi.AsRealNodeGen;
 import com.oracle.truffle.r.nodes.function.CallMatcherNode.CallMatcherGenericNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
-import com.oracle.truffle.r.nodes.function.RCallBaseNode;
-import com.oracle.truffle.r.nodes.function.RCallNode;
-import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
-import com.oracle.truffle.r.nodes.unary.FindFirstNode;
-import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.nodes.function.call.RExplicitBaseEnvCallDispatcher;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -70,7 +65,6 @@ import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
 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.RAbstractVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RFastPathNode;
 
 /**
@@ -106,42 +100,40 @@ public final class SeqFunctions {
     }
 
     @TypeSystemReference(RTypesFlatLayout.class)
-    @SuppressWarnings("unused")
     public abstract static class IsNumericNode extends Node {
         public abstract boolean execute(Object obj);
 
         @Specialization
-        protected boolean isNumericNode(Integer obj) {
+        protected boolean isNumericNode(@SuppressWarnings("unused") Integer obj) {
             return true;
         }
 
         @Specialization
-        protected boolean isNumericNode(Double obj) {
+        protected boolean isNumericNode(@SuppressWarnings("unused") Double obj) {
             return true;
         }
 
         @Specialization
-        protected boolean isNumericNode(RAbstractIntVector obj) {
+        protected boolean isNumericNode(@SuppressWarnings("unused") RAbstractIntVector obj) {
             return true;
         }
 
         @Specialization
-        protected boolean isNumericNode(RAbstractDoubleVector obj) {
+        protected boolean isNumericNode(@SuppressWarnings("unused") RAbstractDoubleVector obj) {
             return true;
         }
 
         @Fallback
-        protected boolean isNumericNode(Object obj) {
+        protected boolean isNumericNode(@SuppressWarnings("unused") Object obj) {
             return false;
         }
     }
 
     @TypeSystemReference(RTypesFlatLayout.class)
-    @SuppressWarnings("unused")
     public abstract static class IsMissingOrNumericNode extends IsNumericNode {
 
         @Specialization
-        protected boolean isMissingOrNumericNode(RMissing obj) {
+        protected boolean isMissingOrNumericNode(@SuppressWarnings("unused") RMissing obj) {
             return true;
         }
     }
@@ -213,15 +205,14 @@ public final class SeqFunctions {
         }
 
         @Specialization(guards = {"!hasClass(args, getClassAttributeNode)"})
-        @SuppressWarnings("unused")
         protected Object seqNoClassAndNumeric(VirtualFrame frame, RArgsValuesAndNames args,
                         @Cached("createSeqIntForFastPath()") SeqInt seqInt,
                         @Cached("lookupSeqInt()") RFunction seqIntFunction,
                         @Cached("createBinaryProfile()") ConditionProfile isNumericProfile,
-                        @Cached("createGetClassAttributeNode()") GetClassAttributeNode getClassAttributeNode,
+                        @Cached("createGetClassAttributeNode()") @SuppressWarnings("unused") GetClassAttributeNode getClassAttributeNode,
                         @Cached("createIsMissingOrNumericNode()") IsMissingOrNumericNode fromCheck,
                         @Cached("createIsMissingOrNumericNode()") IsMissingOrNumericNode toCheck,
-                        @Cached("createIsMissingOrNumericNode()") IsMissingOrNumericNode byCheck) {
+                        @Cached("createIsMissingOrNumericNode()") @SuppressWarnings("unused") IsMissingOrNumericNode byCheck) {
             Object[] rargs = reorderedArguments(args, seqIntFunction);
             if (isNumericProfile.profile(fromCheck.execute(rargs[0]) && toCheck.execute(rargs[1]) && toCheck.execute(rargs[2]))) {
                 return seqInt.execute(frame, rargs[0], rargs[1], rargs[2], rargs[3], rargs[4]);
@@ -230,9 +221,8 @@ public final class SeqFunctions {
             }
         }
 
-        @SuppressWarnings("unused")
         @Fallback
-        protected Object seqFallback(VirtualFrame frame, Object args) {
+        protected Object seqFallback(@SuppressWarnings("unused") Object args) {
             return null;
         }
 
@@ -335,16 +325,26 @@ public final class SeqFunctions {
     public abstract static class SeqAlong extends RBuiltinNode {
         @Child private ClassHierarchyNode classHierarchyNode = ClassHierarchyNode.create();
 
+        static {
+            Casts.noCasts(SeqAlong.class);
+        }
+
         @Specialization(guards = "!hasClass(value)")
         protected RIntSequence seq(VirtualFrame frame, Object value,
                         @Cached("create()") RLengthNode length) {
             return RDataFactory.createIntSequence(1, 1, length.executeInteger(frame, value));
         }
 
+        /**
+         * Invokes the 'length' function, which may dispatch to some other function than the default
+         * length depending on the class of the argument.
+         */
         @Specialization(guards = "hasClass(value)")
         protected RIntSequence seq(VirtualFrame frame, Object value,
-                        @Cached("create()") LengthDispatcher dispatcher) {
-            return RDataFactory.createIntSequence(1, 1, dispatcher.execute(frame, value));
+                        @Cached("createLengthResultCast()") CastNode resultCast,
+                        @Cached("createLengthDispatcher()") RExplicitBaseEnvCallDispatcher dispatcher) {
+            int result = (Integer) resultCast.execute(dispatcher.call(frame, value));
+            return RDataFactory.createIntSequence(1, 1, result);
         }
 
         boolean hasClass(Object obj) {
@@ -352,42 +352,18 @@ public final class SeqFunctions {
             return classVec != null && classVec.getLength() != 0;
         }
 
-        /**
-         * Invokes the 'length' function, which may dispatch to some other function than default
-         * length depending on the class of the argument.
-         */
-        static final class LengthDispatcher extends Node {
-            private final Object argsIdentifier = new Object();
-            private final BranchProfile errorProfile = BranchProfile.create();
-            @Child private RCallBaseNode call = RCallNode.createExplicitCall(argsIdentifier);
-            @Child private FrameSlotNode argumentsSlot = FrameSlotNode.createTemp(argsIdentifier, true);
-            @Child private LocalReadVariableNode readLength = LocalReadVariableNode.create("length", true);
-            @Child private CastIntegerNode castInteger = CastIntegerNode.createNonPreserving();
-            @Child private FindFirstNode findFirst = FindFirstNode.create(Integer.class, NO_CALLER, Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
-
-            public static LengthDispatcher create() {
-                return new LengthDispatcher();
-            }
-
-            public int execute(VirtualFrame frame, Object target) {
-                FrameSlot argsFrameSlot = argumentsSlot.executeFrameSlot(frame);
-                try {
-                    frame.setObject(argsFrameSlot, new RArgsValuesAndNames(new Object[]{target}, ArgumentsSignature.empty(1)));
-                    Object lengthFunction = readLength.execute(frame, REnvironment.baseEnv().getFrame());
-                    int result = castResult(call.execute(frame, lengthFunction));
-                    if (result < 0 || RRuntime.isNA(result)) {
-                        errorProfile.enter();
-                        throw RError.error(NO_CALLER, Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
-                    }
-                    return result;
-                } finally {
-                    frame.setObject(argsFrameSlot, null);
-                }
-            }
+        RExplicitBaseEnvCallDispatcher createLengthDispatcher() {
+            return RExplicitBaseEnvCallDispatcher.create("length");
+        }
 
-            private int castResult(Object result) {
-                return (Integer) findFirst.execute(castInteger.execute(result));
-            }
+        CastNode createLengthResultCast() {
+            // @formatter:off
+            return newCastBuilder().asIntegerVector(false, false, false).
+                    defaultError(NO_CALLER, Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED).
+                    findFirst().
+                    mustBe(gte(0).and(notIntNA())).
+                    buildCastNode();
+            // @formatter:on
         }
     }
 
@@ -395,8 +371,8 @@ public final class SeqFunctions {
     @RBuiltin(name = "seq_len", kind = PRIMITIVE, parameterNames = {"length.out"}, behavior = PURE)
     public abstract static class SeqLen extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SeqLen.class);
             /*
              * This is slightly different than what GNU R does as it will report coercion warning
              * for: seq_len(c("7", "b")) GNU R (presumably) gets the first element before doing a
@@ -448,6 +424,10 @@ public final class SeqFunctions {
 
         private static final double FLT_EPSILON = 1.19209290e-7;
 
+        static {
+            Casts.noCasts(SeqInt.class);
+        }
+
         protected abstract Object execute(VirtualFrame frame, Object start, Object to, Object by, Object lengthOut, Object alongWith);
 
         protected SeqInt(boolean seqFastPath) {
@@ -580,8 +560,8 @@ public final class SeqFunctions {
         /**
          * The performance of this specialization, we assert, is not important. It captures a
          * mixture of coercions from improbable types and error cases. N.B. However, mixing doubles
-         * and ints <b<will</b> hit this specialization; is that likely and a concern? If
-         * "from ==missing", it defaults to 1.0. "to" cannot be missing as that would overlap with
+         * and ints <b<will</b> hit this specialization; is that likely and a concern? If "from
+         * ==missing", it defaults to 1.0. "to" cannot be missing as that would overlap with
          * previous specializations.
          */
         @Specialization(guards = {"!isMissing(toObj)"})
@@ -955,11 +935,11 @@ public final class SeqFunctions {
             return from.getLength() == 1 && to.getLength() == 1 && isFinite(from.getDataAt(0)) && isFinite(to.getDataAt(0));
         }
 
-        public static final boolean validIntParams(RAbstractIntVector from, RAbstractIntVector to) {
+        public static boolean validIntParams(RAbstractIntVector from, RAbstractIntVector to) {
             return validIntParam(from) && validIntParam(to);
         }
 
-        public static final boolean validIntParam(RAbstractIntVector vec) {
+        public static boolean validIntParam(RAbstractIntVector vec) {
             return vec.getLength() == 1 && vec.getDataAt(0) != RRuntime.INT_NA;
         }
 
@@ -967,23 +947,23 @@ public final class SeqFunctions {
             return lengthNode.executeInteger(frame, obj);
         }
 
-        public static final boolean isNumeric(Object obj) {
+        public static boolean isNumeric(Object obj) {
             return obj instanceof Double || obj instanceof Integer || obj instanceof RAbstractDoubleVector || obj instanceof RAbstractIntVector;
         }
 
-        public static final boolean isInt(Object obj) {
+        public static boolean isInt(Object obj) {
             return obj instanceof Integer || obj instanceof RAbstractIntVector;
         }
 
-        public static final boolean isMissing(Object obj) {
+        public static boolean isMissing(Object obj) {
             return obj == RMissing.instance || obj == REmpty.instance;
         }
 
-        public static final boolean oneNotMissing(Object obj1, Object obj2) {
+        public static boolean oneNotMissing(Object obj1, Object obj2) {
             return !isMissing(obj1) || !isMissing(obj2);
         }
 
-        public static final boolean isPositiveIntegralDouble(double d) {
+        public static boolean isPositiveIntegralDouble(double d) {
             int id = (int) d;
             return id == d && id > 0;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java
index eba314bde024d8553dd4316fca31ddeb9492ad6e..82f063958e5b04d6b10fd0637d0f6dc5f43146cc 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java
@@ -35,7 +35,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -86,15 +85,16 @@ public class SerializeFunctions {
             }
         }
 
-        protected void connection(CastBuilder casts) {
-            casts.arg("con").mustNotBeNull().mustBe(integerValue()).asIntegerVector().findFirst();
+        protected static void connection(Casts casts) {
+            casts.arg("con").mustBe(integerValue()).asIntegerVector().findFirst();
         }
     }
 
     @RBuiltin(name = "unserializeFromConn", kind = INTERNAL, parameterNames = {"con", "refhook"}, behavior = IO)
     public abstract static class UnserializeFromConn extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(UnserializeFromConn.class);
             connection(casts);
         }
 
@@ -112,8 +112,9 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "serializeToConn", visibility = OFF, kind = INTERNAL, parameterNames = {"object", "con", "ascii", "version", "refhook"}, behavior = IO)
     public abstract static class SerializeToConn extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SerializeToConn.class);
             connection(casts);
             casts.arg("ascii").mustBe(logicalValue(), RError.Message.ASCII_NOT_LOGICAL);
             casts.arg("version").allowNull().mustBe(integerValue());
@@ -135,9 +136,10 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "unserialize", kind = INTERNAL, parameterNames = {"con", "refhook"}, behavior = IO)
     public abstract static class Unserialize extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustNotBeNull().mustBe(integerValue().or(rawValue())).mapIf(integerValue(),
+
+        static {
+            Casts casts = new Casts(Unserialize.class);
+            casts.arg("con").defaultError(Message.INVALID_CONNECTION).mustBe(integerValue().or(rawValue())).mapIf(integerValue(),
                             asIntegerVector().setNext(findFirst().integerElement()));
         }
 
@@ -154,8 +156,9 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "serialize", kind = INTERNAL, parameterNames = {"object", "con", "type", "version", "refhook"}, behavior = IO)
     public abstract static class Serialize extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Serialize.class);
             casts.arg("con").allowNull().mustBe(integerValue()).asIntegerVector().findFirst();
             casts.arg("type").asIntegerVector().findFirst();
         }
@@ -175,8 +178,9 @@ public class SerializeFunctions {
 
     @RBuiltin(name = "serializeb", kind = INTERNAL, parameterNames = {"object", "con", "xdr", "version", "refhook"}, behavior = IO)
     public abstract static class SerializeB extends Adapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SerializeB.class);
             connection(casts);
             casts.arg("xdr").asLogicalVector().findFirst();
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java
index 4bdc4299075dfc3e6b28ded5dfbce2825880f3f0..49a67b4f48980a143aad02f3f03e8ec02e465df8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetS4Object.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.nodes.objects.AsS4;
 import com.oracle.truffle.r.nodes.objects.AsS4NodeGen;
@@ -45,9 +44,9 @@ public abstract class SetS4Object extends RBuiltinNode {
 
     @Child private AsS4 asS4 = AsS4NodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("object").allowNull().asAttributable(true, true, true);
+    static {
+        Casts casts = new Casts(SetS4Object.class);
+        casts.arg("object").asAttributable(true, true, true);
         casts.arg("flag").asLogicalVector().mustBe(singleElement(), RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "flag").findFirst().map(toBoolean());
         // "complete" can be a vector, unlike "flag"
         casts.arg("complete").asIntegerVector().findFirst(RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "complete");
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
index 12b685c970a6708c7cd4b4d6a25eafd7800575c5..1b89fd845d9dbf51868d1edbe4d16746ce729a44 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SetTimeLimit.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -36,8 +35,8 @@ import com.oracle.truffle.r.runtime.data.RNull;
 @RBuiltin(name = "setTimeLimit", kind = INTERNAL, parameterNames = {"cpu", "elapsed", "transient"}, visibility = OFF, behavior = COMPLEX)
 public abstract class SetTimeLimit extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(SetTimeLimit.class);
         casts.arg("cpu").asDoubleVector().findFirst();
         casts.arg("elapsed").asDoubleVector().findFirst();
         casts.arg("transient").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java
index 9180e76850957de0adc25607cb1ceccbad79fb3b..4c4abf4a6babb76967a8375e9285be5cee6c26e3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Setwd.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,32 +31,34 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 @RBuiltin(name = "setwd", visibility = OFF, kind = INTERNAL, parameterNames = "path", behavior = IO)
 public abstract class Setwd extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Setwd.class);
         casts.arg("path").defaultError(SHOW_CALLER, CHAR_ARGUMENT).mustBe(stringValue()).asStringVector().mustBe(notEmpty()).findFirst();
     }
 
     @Specialization
     @TruffleBoundary
-    protected Object setwd(String path) {
-        String owd = RFFIFactory.getRFFI().getBaseRFFI().getwd();
+    protected Object setwd(String path,
+                    @Cached("create()") BaseRFFI.GetwdNode getwdNode,
+                    @Cached("create()") BaseRFFI.SetwdNode setwdNode) {
+        String owd = getwdNode.execute();
         String nwd = Utils.tildeExpand(path);
-        int rc = RFFIFactory.getRFFI().getBaseRFFI().setwd(nwd);
+        int rc = setwdNode.execute(nwd);
         if (rc != 0) {
             throw RError.error(this, RError.Message.CANNOT_CHANGE_DIRECTORY);
         } else {
-            String nwdAbs = RFFIFactory.getRFFI().getBaseRFFI().getwd();
+            String nwdAbs = getwdNode.execute();
             Utils.updateCurwd(nwdAbs);
             return owd;
         }
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 17a035de4a7ff78c82f6ecf809bc11439af6a064..eed5de7dd1ead62987cd2954a548cc3fbb369516 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ 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;
@@ -51,8 +50,8 @@ public abstract class ShortRowNames extends RBuiltinNode {
 
     @Child private GetRowNamesAttributeNode getRowNamesNode = GetRowNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ShortRowNames.class);
         casts.arg("type").asIntegerVector().findFirst().mustBe(gte0().and(lte(2)));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java
index 6ec1fc1d5e8c7db52f187dcc8905b6e7ff09bc20..5c3afc71a88a397a4839c202e2362c4c5ed9fcb3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Signif.java
@@ -40,7 +40,6 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNodeGen;
-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.RInternalError;
@@ -69,8 +68,8 @@ public abstract class Signif extends RBuiltinNode {
     private final BranchProfile identity = BranchProfile.create();
     private final ConditionProfile infProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Signif.class);
         casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustBe(numericValue().or(complexValue())).mapIf(complexValue().not(),
                         asDoubleVector(true, true, true));
         // TODO: for the error messages to be consistent with GNU R we should chack for notEmpty()
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java
index b688de5f2f3f3423e9c5f3f28ba5e49ddc30b1fc..9ae7473c5fd527622e26ee63b9dbc4cb88343566 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SinkFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
@@ -31,8 +32,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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;
@@ -43,9 +42,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 public class SinkFunctions {
     @RBuiltin(name = "sink", visibility = OFF, kind = INTERNAL, parameterNames = {"file", "closeOnExit", "type", "split"}, behavior = IO)
     public abstract static class Sink extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg("file").mustNotBeNull().mustBe(Predef.integerValue()).asIntegerVector().findFirst();
+
+        static {
+            Casts casts = new Casts(Sink.class);
+            casts.arg("file").mustBe(integerValue()).asIntegerVector().findFirst();
             casts.arg("closeOnExit").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("type").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("split").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -78,8 +78,9 @@ public class SinkFunctions {
 
     @RBuiltin(name = "sink.number", kind = INTERNAL, parameterNames = {"type"}, behavior = IO)
     public abstract static class SinkNumber extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SinkNumber.class);
             casts.arg("type").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
index 6c4e907480e70cdc8229dd55ea3bcca78968b29f..b785bc5ddd4cfc6dc4d3d34e8c540c729dc1a3fb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Slot.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -24,7 +24,6 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.WrapArgumentNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -36,11 +35,11 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
 @RBuiltin(name = "@", kind = PRIMITIVE, parameterNames = {"", ""}, nonEvalArgs = 1, behavior = COMPLEX)
 public abstract class Slot extends RBuiltinNode {
 
-    @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(true, null, null);
+    @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(true);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(0).allowNull().asAttributable(true, true, true);
+    static {
+        Casts casts = new Casts(Slot.class);
+        casts.arg(0).asAttributable(true, true, true);
     }
 
     private String getName(Object nameObj) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java
index 85bd174365a0e2f180837ab14f89ac8161630549..7ae1a1ce6eca3d86d4648f695d9b339797771d41 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SortFunctions.java
@@ -36,7 +36,6 @@ import java.util.Collections;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -60,12 +59,12 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public class SortFunctions {
 
     private abstract static class Adapter extends RBuiltinNode {
-        protected static void addCastForX(CastBuilder castBuilder) {
-            castBuilder.arg("x").allowNull().mustBe(abstractVectorValue(), SHOW_CALLER, ONLY_ATOMIC_CAN_BE_SORTED);
+        protected static void addCastForX(Casts casts) {
+            casts.arg("x").allowNull().mustBe(abstractVectorValue(), SHOW_CALLER, ONLY_ATOMIC_CAN_BE_SORTED);
         }
 
-        protected static void addCastForDecreasing(CastBuilder castBuilder) {
-            castBuilder.arg("decreasing").defaultError(SHOW_CALLER, INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().map(toBoolean());
+        protected static void addCastForDecreasing(Casts casts) {
+            casts.arg("decreasing").defaultError(SHOW_CALLER, INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().map(toBoolean());
         }
 
         @TruffleBoundary
@@ -152,8 +151,8 @@ public class SortFunctions {
     @RBuiltin(name = "sort", kind = INTERNAL, parameterNames = {"x", "decreasing"}, behavior = PURE)
     public abstract static class Sort extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Sort.class);
             addCastForX(casts);
             addCastForDecreasing(casts);
         }
@@ -182,8 +181,8 @@ public class SortFunctions {
     @RBuiltin(name = "qsort", kind = INTERNAL, parameterNames = {"x", "decreasing"}, behavior = PURE)
     public abstract static class QSort extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(QSort.class);
             addCastForX(casts);
             addCastForDecreasing(casts);
         }
@@ -202,8 +201,8 @@ public class SortFunctions {
     @RBuiltin(name = "psort", kind = INTERNAL, parameterNames = {"x", "partial"}, behavior = PURE)
     public abstract static class PartialSort extends Adapter {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(PartialSort.class);
             addCastForX(casts);
         }
 
@@ -242,8 +241,8 @@ public class SortFunctions {
     public abstract static class RadixSort extends Adapter {
         @Child private Order orderNode = OrderNodeGen.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(RadixSort.class);
             casts.arg("na.last").asLogicalVector().findFirst();
             casts.arg("decreasing").mustBe(numericValue(), SHOW_CALLER, INVALID_LOGICAL, "decreasing").asLogicalVector();
             casts.arg("retgrp").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
index 196ccc3cfa67dbe2260bad263fb742c9522f5636..b43d2e7fc99f702010a8b8dc62359b7caa97faad 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
@@ -58,6 +58,10 @@ public abstract class Split extends RBuiltinNode {
     private static final int INITIAL_SIZE = 5;
     private static final int SCALE_FACTOR = 2;
 
+    static {
+        Casts.noCasts(Split.class);
+    }
+
     public static class SplitTemplate {
         @SuppressWarnings("unused") private int[] collectResultsSize;
         @SuppressWarnings("unused") private int nLevels;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java
index a18ee23a793b911520dc0b9359999da104b20040..1a47d84f964031ec045edef55899b04c91a727c1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java
@@ -45,8 +45,13 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "sprintf", kind = INTERNAL, parameterNames = {"fmt", "..."}, behavior = PURE)
+
 public abstract class Sprintf extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(Sprintf.class);
+    }
+
     public abstract Object executeObject(String fmt, Object args);
 
     @Child private Sprintf sprintfRecursive;
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 241c5ff0c6e325897adb3af7268dcb7519438571..9ca4d012ee7ee4ffb39ff638f80dd06d19859e5c 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
@@ -15,6 +15,7 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lengthGt;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
 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;
@@ -31,10 +32,8 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNode;
-import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNodeGen;
 import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNode;
 import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNodeGen;
 import com.oracle.truffle.r.nodes.objects.DispatchGeneric;
@@ -67,34 +66,22 @@ public abstract class StandardGeneric extends RBuiltinNode {
     @Child private LocalReadVariableNode readSigARgs = LocalReadVariableNode.create(RRuntime.DOT_SIG_ARGS, true);
     @Child private CollectGenericArgumentsNode collectArgumentsNode;
     @Child private DispatchGeneric dispatchGeneric = DispatchGenericNodeGen.create();
-    @Child private ClassHierarchyScalarNode classNode;
 
     @Child private CastNode castIntScalar;
     @Child private CastNode castStringScalar;
     {
-        CastBuilder builder = new CastBuilder(2);
-        builder.arg(0).asIntegerVector().findFirst(RRuntime.INT_NA);
-        builder.arg(1).asStringVector().findFirst(RRuntime.STRING_NA);
-        castIntScalar = builder.getCasts()[0];
-        castStringScalar = builder.getCasts()[1];
+        castIntScalar = newCastBuilder().asIntegerVector().findFirst(RRuntime.INT_NA).buildCastNode();
+        castStringScalar = newCastBuilder().asStringVector().findFirst(RRuntime.STRING_NA).buildCastNode();
     }
 
     private final BranchProfile noGenFunFound = BranchProfile.create();
     private final ConditionProfile sameNamesProfile = ConditionProfile.createBinaryProfile();
 
-    private String argClass(Object arg) {
-        if (classNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            classNode = insert(ClassHierarchyScalarNodeGen.create());
-        }
-        return classNode.executeString(arg);
-    }
-
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(StandardGeneric.class);
         casts.arg("f").defaultError(RError.Message.GENERIC, "argument to 'standardGeneric' must be a non-empty character string").mustBe(
                         stringValue()).asStringVector().findFirst().mustBe(lengthGt(0));
-        Function<Object, Object> argClass = this::argClass;
+        Function<Object, Object> argClass = ClassHierarchyScalarNode::get;
         casts.arg("fdef").defaultError(RError.SHOW_CALLER, RError.Message.EXPECTED_GENERIC, argClass).allowMissing().asAttributable(true, true, true).mustBe(instanceOf(RFunction.class));
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java
index 361eaeb24a56e85928d45bac0790fbf8e50c4635..32242b09d479d77c98832aece324b779a1445c39 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StartsEndsWithFunctions.java
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-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;
@@ -38,20 +37,20 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public class StartsEndsWithFunctions {
-    private static class Casts {
-        private static void arg(CastBuilder casts, String name) {
-            casts.arg(name).mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER_OBJECTS).asStringVector();
-        }
-    }
 
     private abstract static class Adapter extends RBuiltinNode {
         private final NACheck naCheck = NACheck.create();
         private final ConditionProfile singlePrefixProfile = ConditionProfile.createBinaryProfile();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.arg(casts, "x");
-            Casts.arg(casts, "prefix");
+        private static void argCast(Casts casts, String name) {
+            casts.arg(name).mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.NON_CHARACTER_OBJECTS).asStringVector();
+        }
+
+        protected static Casts createCasts(Class<? extends Adapter> extCls) {
+            Casts casts = new Casts(extCls);
+            argCast(casts, "x");
+            argCast(casts, "prefix");
+            return casts;
         }
 
         protected Object doIt(RAbstractStringVector xVec, RAbstractStringVector prefixVec, boolean startsWith) {
@@ -97,6 +96,11 @@ public class StartsEndsWithFunctions {
 
     @RBuiltin(name = "startsWith", kind = INTERNAL, parameterNames = {"x", "prefix"}, behavior = PURE)
     public abstract static class StartsWith extends Adapter {
+
+        static {
+            createCasts(StartsWith.class);
+        }
+
         @Specialization
         protected Object startsWith(RAbstractStringVector x, RAbstractStringVector prefix) {
             return doIt(x, prefix, true);
@@ -106,6 +110,10 @@ public class StartsEndsWithFunctions {
     @RBuiltin(name = "endsWith", kind = INTERNAL, parameterNames = {"x", "prefix"}, behavior = PURE)
     public abstract static class EndsWith extends Adapter {
 
+        static {
+            createCasts(EndsWith.class);
+        }
+
         @Specialization
         protected Object endsWith(RAbstractStringVector x, RAbstractStringVector prefix) {
             return doIt(x, prefix, false);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java
index 44e3885490df21a52a38b543ea10413679a2fa49..efb1ada9f48b86cc105facbdc6b621367404c7c2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Stop.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
 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.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -38,8 +37,9 @@ import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = "stop", kind = INTERNAL, parameterNames = {"call", "message"}, behavior = COMPLEX)
 public abstract class Stop extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(Stop.class);
         casts.arg("call").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("message").allowNull().mustBe(stringValue()).asStringVector().mustBe(notEmpty(), RError.Message.INVALID_STRING_IN_STOP).findFirst();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java
index 42746aea682f166ace97507fa447cc4fc884eaaf..6710bae7b4cab953d06866004c5da948a3a14f21 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strrep.java
@@ -27,7 +27,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class Strrep extends RBuiltinNode {
     private final NACheck naCheck = NACheck.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Strrep.class);
         casts.arg("x").asStringVector();
         casts.arg("times").asIntegerVector();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java
index ce5653198a3d926047cf1bafafbb16a6b17e4808..86e2c0b11b9505253434ebbe8d8cf6805ccf9219 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ 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.PrimitiveValueProfile;
-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;
@@ -46,8 +45,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "strtoi", kind = INTERNAL, parameterNames = {"x", "base"}, behavior = PURE)
 public abstract class Strtoi extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Strtoi.class);
         casts.arg("x").mustBe(stringValue()).asStringVector();
         // base == 0 || (base >= 2 && base <= 36)
         casts.arg("base").mustBe(integerValue()).asIntegerVector().findFirst().mustBe(eq(0).or(gte(2).and(lte(36))));
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java
index fa27e232c3ef00046c3744d4419b77e1c5e39332..9fb1980325dc7f5fa7887cd8d9b6088efd8e4472 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2016, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -23,7 +23,6 @@ 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.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.ToLowerOrUpper.StringMapNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -37,8 +36,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "strtrim", kind = INTERNAL, parameterNames = {"x", "width"}, behavior = PURE)
 public abstract class Strtrim extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Strtrim.class);
         casts.arg("x").defaultError(Message.REQUIRES_CHAR_VECTOR, "strtrim()").mustBe(stringValue()).asStringVector(true, true, true);
         casts.arg("width").asIntegerVector();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java
index f6077ad1c69a944453c2c1ed3298e0555b525425..8f75d3805283f2630e15b5072874c9e3b4d7c5fe 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java
@@ -26,20 +26,25 @@ 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.Fallback;
+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.library.methods.SubstituteDirect;
 import com.oracle.truffle.r.nodes.RASTUtils;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.RList2EnvNode;
 import com.oracle.truffle.r.nodes.control.IfNode;
-import com.oracle.truffle.r.runtime.RError;
+import static com.oracle.truffle.r.runtime.RError.Message.INVALID_ENVIRONMENT_SPECIFIED;
 import com.oracle.truffle.r.runtime.RSubstitute;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 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.RPromise;
 import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "substitute", kind = PRIMITIVE, parameterNames = {"expr", "env"}, nonEvalArgs = 0, behavior = COMPLEX)
@@ -47,24 +52,35 @@ public abstract class Substitute extends RBuiltinNode {
 
     @Child private Quote quote;
 
+    static {
+        Casts casts = new Casts(Substitute.class);
+        casts.arg(1).allowNullAndMissing().defaultError(INVALID_ENVIRONMENT_SPECIFIED).mustBe(instanceOf(RAbstractListVector.class).or(instanceOf(REnvironment.class)));
+    }
+
     @Specialization
     protected Object doSubstitute(VirtualFrame frame, RPromise expr, @SuppressWarnings("unused") RMissing envMissing) {
         return doSubstituteWithEnv(expr, REnvironment.frameToEnvironment(frame.materialize()));
     }
 
+    @Specialization
+    protected Object doSubstitute(VirtualFrame frame, RPromise expr, @SuppressWarnings("unused") RNull env) {
+        return doSubstituteWithEnv(expr, REnvironment.frameToEnvironment(frame.materialize()));
+    }
+
     @Specialization
     protected Object doSubstitute(RPromise expr, REnvironment env) {
         return doSubstituteWithEnv(expr, env);
     }
 
-    @Specialization
+    @Specialization(guards = {"list.getNames() == null || list.getNames().getLength() == 0"})
     protected Object doSubstitute(RPromise expr, RList list) {
-        return doSubstituteWithEnv(expr, REnvironment.createFromList(list, REnvironment.baseEnv()));
+        return doSubstituteWithEnv(expr, SubstituteDirect.createNewEnvironment());
     }
 
-    @Fallback
-    protected Object doSubstitute(@SuppressWarnings("unused") Object expr, @SuppressWarnings("unused") Object x) {
-        throw RError.error(this, RError.Message.INVALID_ENVIRONMENT);
+    @Specialization(guards = {"list.getNames() != null", "list.getNames().getLength() > 0"})
+    protected Object doSubstitute(RPromise expr, RList list,
+                    @Cached("createList2EnvNode()") RList2EnvNode list2Env) {
+        return doSubstituteWithEnv(expr, SubstituteDirect.createEnvironment(list, list2Env));
     }
 
     /**
@@ -95,4 +111,9 @@ public abstract class Substitute extends RBuiltinNode {
         // so get the actual expression (AST) from that
         return RASTUtils.createLanguageElement(RSubstitute.substitute(env, expr.getRep()));
     }
+
+    protected static RList2EnvNode createList2EnvNode() {
+        return new RList2EnvNode(true);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java
index eec79076483a486ef103eaa62fbfc9f3f9a28651..b55b50f9431765f56c66c64914e0a0e07c12b3ea 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substr.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,10 @@ public abstract class Substr extends RBuiltinNode {
     private final BranchProfile everSeenIllegalRange = BranchProfile.create();
     private final ConditionProfile naIndexesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Substr.class);
+    }
+
     @SuppressWarnings("unused")
     @Specialization(guards = "emptyArg(arg)")
     protected RStringVector substrEmptyArg(VirtualFrame frame, RAbstractStringVector arg, RAbstractIntVector start, RAbstractIntVector stop) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
index e28676426c4afbcf6105c2b6a652e1e96a14228b..b8a914baf11c67dbfe8b66755ee5d500272c3c6f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
@@ -31,7 +31,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticReduceNode;
@@ -59,9 +58,9 @@ public abstract class Sum extends RBuiltinNode {
 
     @Child private UnaryArithmeticReduceNode reduce = UnaryArithmeticReduceNodeGen.create(semantics, BinaryArithmetic.ADD);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("na.rm").allowNull().asLogicalVector().findFirst().map(toBoolean());
+    static {
+        Casts casts = new Casts(Sum.class);
+        casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_NA).map(toBoolean());
     }
 
     @Override
@@ -103,12 +102,12 @@ public abstract class Sum extends RBuiltinNode {
         }
     }
 
-    @Specialization(contains = "sumLengthOneRDoubleVector", guards = "args.getLength() == 1")
+    @Specialization(replaces = "sumLengthOneRDoubleVector", guards = "args.getLength() == 1")
     protected Object sumLengthOne(RArgsValuesAndNames args, boolean naRm) {
         return reduce.executeReduce(args.getArgument(0), naRm, false);
     }
 
-    @Specialization(contains = {"sumLengthOneRDoubleVector", "sumLengthOne"})
+    @Specialization(replaces = {"sumLengthOneRDoubleVector", "sumLengthOne"})
     protected Object sum(RArgsValuesAndNames args, boolean naRm,
                     @Cached("create()") Combine combine) {
         return reduce.executeReduce(combine.executeCombine(args, false), naRm, false);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java
index 50ea531bd0b278783ad912f9f615f84edc33f1eb..d1af871ffb367e3cde17326d76c03714d445bfd7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -59,6 +59,10 @@ public abstract class Switch extends RBuiltinNode {
     private final BranchProfile notIntType = BranchProfile.create();
     private final ConditionProfile noAlternativesProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(Switch.class);
+    }
+
     @Specialization
     protected Object doSwitch(VirtualFrame frame, RAbstractStringVector x, RArgsValuesAndNames optionalArgs) {
         if (x.getLength() != 1) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
index e62c27d3e45cdc1ca7a0623ead849a614c8377ac..cc35e6facb3475aecbfbf0572f472696085adbb7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java
@@ -45,13 +45,13 @@ import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 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.Frame;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages;
 import com.oracle.truffle.r.runtime.RArguments;
@@ -68,17 +68,19 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI.UtsName;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public class SysFunctions {
 
     @RBuiltin(name = "Sys.getpid", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
     public abstract static class SysGetpid extends RBuiltinNode {
+        @Child private BaseRFFI.GetpidNode getpidNode = BaseRFFI.GetpidNode.create();
+
         @Specialization
         @TruffleBoundary
         protected Object sysGetPid() {
-            int pid = RFFIFactory.getRFFI().getBaseRFFI().getpid();
+            int pid = getpidNode.execute();
             return RDataFactory.createIntVectorFromScalar(pid);
         }
     }
@@ -87,8 +89,8 @@ public class SysFunctions {
     public abstract static class SysGetenv extends RBuiltinNode {
         private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(SysGetenv.class);
             casts.arg("x").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
             casts.arg("unset").mustBe(stringValue()).asStringVector().mustBe(size(1)).findFirst();
         }
@@ -160,8 +162,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.setenv", visibility = OFF, kind = INTERNAL, parameterNames = {"nm", "values"}, behavior = MODIFIES_STATE)
     public abstract static class SysSetEnv extends LoadNamespaceAdapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysSetEnv.class);
             casts.arg("nm").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
             casts.arg("values").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
         }
@@ -189,8 +192,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.unsetenv", visibility = OFF, kind = INTERNAL, parameterNames = {"x"}, behavior = READS_STATE)
     public abstract static class SysUnSetEnv extends LoadNamespaceAdapter {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysUnSetEnv.class);
             casts.arg("x").mustBe(stringValue(), RError.Message.ARGUMENT_WRONG_TYPE);
         }
 
@@ -214,8 +218,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.sleep", visibility = OFF, kind = INTERNAL, parameterNames = {"time"}, behavior = COMPLEX)
     public abstract static class SysSleep extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysSleep.class);
             casts.arg("time").asDoubleVector().findFirst().mustBe(gte(0.0).and(eq(Double.NaN).not()));
         }
 
@@ -244,14 +249,16 @@ public class SysFunctions {
      */
     @RBuiltin(name = "Sys.readlink", kind = INTERNAL, parameterNames = {"paths"}, behavior = IO)
     public abstract static class SysReadlink extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysReadlink.class);
             casts.arg("paths").mustBe(stringValue());
         }
 
         @Specialization
         @TruffleBoundary
-        protected Object sysReadlink(RAbstractStringVector vector) {
+        protected Object sysReadlink(RAbstractStringVector vector,
+                        @Cached("create()") BaseRFFI.ReadlinkNode readlinkNode) {
             String[] paths = new String[vector.getLength()];
             boolean complete = RDataFactory.COMPLETE_VECTOR;
             for (int i = 0; i < paths.length; i++) {
@@ -259,7 +266,7 @@ public class SysFunctions {
                 if (RRuntime.isNA(path)) {
                     paths[i] = path;
                 } else {
-                    paths[i] = doSysReadLink(path);
+                    paths[i] = doSysReadLink(path, readlinkNode);
                 }
                 if (RRuntime.isNA(paths[i])) {
                     complete = RDataFactory.INCOMPLETE_VECTOR;
@@ -269,10 +276,10 @@ public class SysFunctions {
         }
 
         @TruffleBoundary
-        private static String doSysReadLink(String path) {
+        private static String doSysReadLink(String path, BaseRFFI.ReadlinkNode readlinkNode) {
             String s;
             try {
-                s = RFFIFactory.getRFFI().getBaseRFFI().readlink(path);
+                s = readlinkNode.execute(path);
                 if (s == null) {
                     s = "";
                 }
@@ -285,8 +292,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.chmod", visibility = OFF, kind = INTERNAL, parameterNames = {"paths", "octmode", "use_umask"}, behavior = IO)
     public abstract static class SysChmod extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysChmod.class);
             casts.arg("paths").mustBe(stringValue());
             casts.arg("octmode").asIntegerVector().mustBe(notEmpty(), RError.Message.MODE_LENGTH_ONE);
             casts.arg("use_umask").asLogicalVector().findFirst().notNA().map(toBoolean());
@@ -294,14 +302,15 @@ public class SysFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected RLogicalVector sysChmod(RAbstractStringVector pathVec, RAbstractIntVector octmode, @SuppressWarnings("unused") boolean useUmask) {
+        protected RLogicalVector sysChmod(RAbstractStringVector pathVec, RAbstractIntVector octmode, @SuppressWarnings("unused") boolean useUmask,
+                        @Cached("create()") BaseRFFI.ChmodNode chmodNode) {
             byte[] data = new byte[pathVec.getLength()];
             for (int i = 0; i < data.length; i++) {
                 String path = Utils.tildeExpand(pathVec.getDataAt(i));
                 if (path.length() == 0 || RRuntime.isNA(path)) {
                     continue;
                 }
-                int result = RFFIFactory.getRFFI().getBaseRFFI().chmod(path, octmode.getDataAt(i % octmode.getLength()));
+                int result = chmodNode.execute(path, octmode.getDataAt(i % octmode.getLength()));
                 data[i] = RRuntime.asLogical(result == 0);
             }
             return RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR);
@@ -311,8 +320,9 @@ public class SysFunctions {
     // TODO implement
     @RBuiltin(name = "Sys.umask", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"octmode"}, behavior = COMPLEX)
     public abstract static class SysUmask extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysUmask.class);
             casts.arg("octmode").asIntegerVector().findFirst();
         }
 
@@ -338,10 +348,12 @@ public class SysFunctions {
         private static final String[] NAMES = new String[]{"sysname", "release", "version", "nodename", "machine", "login", "user", "effective_user"};
         private static final RStringVector NAMES_ATTR = RDataFactory.createStringVector(NAMES, RDataFactory.COMPLETE_VECTOR);
 
+        @Child private BaseRFFI.UnameNode unameNode = BaseRFFI.UnameNode.create();
+
         @Specialization
         @TruffleBoundary
         protected Object sysTime() {
-            UtsName utsname = RFFIFactory.getRFFI().getBaseRFFI().uname();
+            UtsName utsname = unameNode.execute();
             String[] data = new String[NAMES.length];
             data[0] = utsname.sysname();
             data[1] = utsname.release();
@@ -359,15 +371,17 @@ public class SysFunctions {
 
     @RBuiltin(name = "Sys.glob", kind = INTERNAL, parameterNames = {"paths", "dirmask"}, behavior = IO)
     public abstract static class SysGlob extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysGlob.class);
             casts.arg("paths").mustBe(stringValue()).asStringVector();
             casts.arg("dirmask").asLogicalVector().findFirst().notNA().map(toBoolean());
         }
 
         @Specialization
         @TruffleBoundary
-        protected Object sysGlob(RAbstractStringVector pathVec, @SuppressWarnings("unused") boolean dirMask) {
+        protected Object sysGlob(RAbstractStringVector pathVec, @SuppressWarnings("unused") boolean dirMask,
+                        @Cached("create()") BaseRFFI.GlobNode globNode) {
             ArrayList<String> matches = new ArrayList<>();
             // Sys.glob closure already called path.expand
             for (int i = 0; i < pathVec.getLength(); i++) {
@@ -375,7 +389,7 @@ public class SysFunctions {
                 if (pathPattern.length() == 0 || RRuntime.isNA(pathPattern)) {
                     continue;
                 }
-                ArrayList<String> pathPatternMatches = RFFIFactory.getRFFI().getBaseRFFI().glob(pathPattern);
+                ArrayList<String> pathPatternMatches = globNode.glob(pathPattern);
                 matches.addAll(pathPatternMatches);
             }
             String[] data = new String[matches.size()];
@@ -386,8 +400,9 @@ public class SysFunctions {
 
     @RBuiltin(name = "setFileTime", kind = INTERNAL, parameterNames = {"path", "time"}, visibility = OFF, behavior = IO)
     public abstract static class SysSetFileTime extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(SysSetFileTime.class);
             casts.arg("path").mustBe(stringValue()).asStringVector().findFirst();
             casts.arg("time").asIntegerVector().findFirst().notNA();
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java
index f6ac5b31210db26838958d33ad7ecafc6cb2f19d..bbe48d983e50afa4cf6352fcb2e9c01ac3342efd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Tabulate.java
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
-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;
@@ -31,8 +30,8 @@ public abstract class Tabulate extends RBuiltinNode {
 
     private final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Tabulate.class);
         casts.arg("bin").defaultError(RError.NO_CALLER, RError.Message.INVALID_INPUT).mustBe(integerValue()).asIntegerVector();
         casts.arg("nbins").defaultError(RError.NO_CALLER, RError.Message.INVALID_ARGUMENT, "nbin").asIntegerVector().findFirst().mustBe(gte(0));
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempFile.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempFile.java
index 1d365eb082516038eb1ddecddd036f6add06b110..2bb1e17c5c3b177e8234a19de9fb86254b74301a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempFile.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempFile.java
@@ -29,7 +29,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RError;
 import com.oracle.truffle.r.runtime.TempPathName;
@@ -42,8 +41,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = "tempfile", kind = INTERNAL, parameterNames = {"pattern", "tempdir", "fileext"}, behavior = COMPLEX)
 public abstract class TempFile extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(TempFile.class);
         casts.arg("pattern").asVector().mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.INVALID_FILENAME_PATTERN).mustBe(notEmpty(), RError.SHOW_CALLER, RError.Message.NO, "pattern");
         casts.arg("tempdir").asVector().mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.INVALID_VALUE, "tempdir").findFirst(RError.SHOW_CALLER, RError.Message.NO, "tempdir");
         casts.arg("fileext").asVector().mustBe(stringValue(), RError.SHOW_CALLER, RError.Message.INVALID_FILE_EXT).mustBe(notEmpty(), RError.SHOW_CALLER, RError.Message.NO, "fileext");
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 31023607abacfbcd6dffea008880f47efebf75ec..92d3eb1c98b110834b76f3ca6de0c7dd5ab6df48 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ 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;
@@ -95,8 +94,8 @@ public abstract class ToLowerOrUpper {
 
         @Child private StringMapNode mapNode = StringMapNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ToLower.class);
             casts.arg(0, "x").mustBe(stringValue()).asStringVector(true, true, true);
         }
 
@@ -121,8 +120,8 @@ public abstract class ToLowerOrUpper {
 
         @Child private StringMapNode mapNode = StringMapNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ToUpper.class);
             casts.arg(0, "x").mustBe(stringValue()).asStringVector(true, true, true);
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
index fd0b85afe1c23a1ba4c0168b26803404b84d35a2..5521a01b4d0244172289017dce886884108a7391 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,7 +44,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.api.frame.VirtualFrame;
-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;
 import com.oracle.truffle.r.nodes.builtin.helpers.TraceHandling;
@@ -70,12 +69,11 @@ public class TraceFunctions {
     private abstract static class PrimTraceAdapter extends RBuiltinNode {
         @Child private GetFunctions.Get getNode;
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            // @formatter:off
-            casts.arg("what").mustBe(instanceOf(RFunction.class).or(stringValue()), SHOW_CALLER, Message.ARG_MUST_BE_FUNCTION).
-                    mapIf(stringValue(), chain(asStringVector()).with(findFirst().stringElement()).end());
-            // @formatter:on
+        protected static Casts createCasts(Class<? extends PrimTraceAdapter> extCls) {
+            Casts casts = new Casts(extCls);
+            casts.arg("what").mustBe(instanceOf(RFunction.class).or(stringValue()), SHOW_CALLER, Message.ARG_MUST_BE_FUNCTION).mapIf(stringValue(),
+                            chain(asStringVector()).with(findFirst().stringElement()).end());
+            return casts;
         }
 
         protected Object getFunction(VirtualFrame frame, String funcName) {
@@ -90,6 +88,10 @@ public class TraceFunctions {
     @RBuiltin(name = ".primTrace", visibility = OFF, kind = PRIMITIVE, parameterNames = "what", behavior = COMPLEX)
     public abstract static class PrimTrace extends PrimTraceAdapter {
 
+        static {
+            createCasts(PrimTrace.class);
+        }
+
         @Specialization
         protected RNull primTrace(VirtualFrame frame, RAbstractStringVector funcName) {
             return primTrace((RFunction) getFunction(frame, funcName.getDataAt(0)));
@@ -110,6 +112,10 @@ public class TraceFunctions {
     @RBuiltin(name = ".primUntrace", visibility = OFF, kind = PRIMITIVE, parameterNames = "what", behavior = COMPLEX)
     public abstract static class PrimUnTrace extends PrimTraceAdapter {
 
+        static {
+            createCasts(PrimUnTrace.class);
+        }
+
         @Specialization
         protected RNull primUnTrace(VirtualFrame frame, RAbstractStringVector funcName) {
             return primUnTrace((RFunction) getFunction(frame, funcName.getDataAt(0)));
@@ -127,6 +133,11 @@ public class TraceFunctions {
 
     @RBuiltin(name = "traceOnOff", kind = INTERNAL, parameterNames = "state", behavior = COMPLEX)
     public abstract static class TraceOnOff extends RBuiltinNode {
+
+        static {
+            Casts.noCasts(TraceOnOff.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected byte traceOnOff(byte state) {
@@ -189,7 +200,7 @@ public class TraceFunctions {
         protected static String getStackTrace() {
             final StringBuffer result = new StringBuffer();
             Truffle.getRuntime().iterateFrames(frame -> {
-                Frame unwrapped = RArguments.unwrap(frame.getFrame(FrameAccess.READ_ONLY, true));
+                Frame unwrapped = RArguments.unwrap(frame.getFrame(FrameAccess.READ_ONLY));
                 if (RArguments.isRFrame(unwrapped)) {
                     RCaller call = RArguments.getCall(unwrapped);
                     if (call != null && call.isValidCaller()) {
@@ -220,8 +231,9 @@ public class TraceFunctions {
      */
     @RBuiltin(name = "tracemem", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX)
     public abstract static class Tracemem extends TracememBase {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Tracemem.class);
             casts.arg("x").mustNotBeNull(Message.TRACEMEM_NOT_NULL);
         }
 
@@ -242,8 +254,8 @@ public class TraceFunctions {
 
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Retracemem.class);
             casts.arg("previous").defaultError(Message.INVALID_ARGUMENT, "previous").allowNullAndMissing().mustBe(stringValue());
         }
 
@@ -281,6 +293,11 @@ public class TraceFunctions {
 
     @RBuiltin(name = "untracemem", kind = PRIMITIVE, visibility = OFF, parameterNames = "x", behavior = COMPLEX)
     public abstract static class Untracemem extends TracememBase {
+
+        static {
+            Casts.noCasts(Untracemem.class);
+        }
+
         @Specialization
         @TruffleBoundary
         protected RNull execute(Object x) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java
index fca379d84142ae6ae0350162429fc636a0f311ba..4c75e21ae311d40cd313575f18a934798e8a30a8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Traceback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -36,8 +35,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "traceback", kind = INTERNAL, parameterNames = {"x"}, behavior = COMPLEX)
 public abstract class Traceback extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Traceback.class);
         casts.arg("x").mustBe(numericValue()).asIntegerVector().findFirst();
     }
 
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 f264855e7e247876ee24c162f2442ead75a88a7b..f9c7bf4af7be07a22ab8a39d1f214ec0325b04e5 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
@@ -65,6 +65,10 @@ public abstract class Transpose extends RBuiltinNode {
     @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
     @Child private GetDimAttributeNode getDimNode;
 
+    static {
+        Casts.noCasts(Transpose.class);
+    }
+
     public abstract Object execute(RAbstractVector o);
 
     @FunctionalInterface
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java
index 21efb2c61f2f6a0184dfa5fb9533a81314a41570..9839f2e54c92dd1172cd6c1df3c1f38ca1ef2518 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TrigExpFunctions.java
@@ -35,7 +35,6 @@ 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.LoopConditionProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.TrigExpFunctionsFactory.AcosNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.TrigExpFunctionsFactory.AsinNodeGen;
@@ -495,8 +494,8 @@ public class TrigExpFunctions {
         private final NACheck yNACheck = NACheck.create();
         private final NACheck xNACheck = NACheck.create();
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Atan2.class);
             casts.arg(0).mapIf(numericValue(), asDoubleVector());
             casts.arg(1).mapIf(numericValue(), asDoubleVector());
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java
index 3d0e13e8a458fc6d6d11fbe93943b603e41c7ff3..759597b4bcf5180f1955d47e6d3bcb2041856261 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Trunc.java
@@ -31,7 +31,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNodeGen;
@@ -48,16 +47,10 @@ public abstract class Trunc extends RBuiltinNode {
     @Child private BoxPrimitiveNode boxPrimitive = BoxPrimitiveNodeGen.create();
     @Child private UnaryArithmeticNode trunc = UnaryArithmeticNodeGen.create(TRUNC, RError.Message.NON_NUMERIC_MATH, RType.Double);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        //@formatter:off
-        casts.arg("x").
-            defaultError(this, RError.Message.NON_NUMERIC_MATH).
-            mustNotBeNull().
-            mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).
-            mustBe(numericValue()).
-            asDoubleVector(true, true, true);
-        //@formatter:on
+    static {
+        Casts casts = new Casts(Trunc.class);
+        casts.arg("x").defaultError(RError.Message.NON_NUMERIC_MATH).mustNotBeNull().mustBe(complexValue().not(), RError.Message.UNIMPLEMENTED_COMPLEX_FUN).mustBe(numericValue()).asDoubleVector(true,
+                        true, true);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
index 735a4bf0e9a60da03b744aec6d278dc7ad546c6f..1366ac09fab02734ec974acab00d35836b115e31 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Typeof.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,10 @@ public abstract class Typeof extends RBuiltinNode {
 
     @Child private TypeofNode typeofNode = TypeofNodeGen.create();
 
+    static {
+        Casts.noCasts(Typeof.class);
+    }
+
     @Specialization
     protected String typeof(Object obj) {
         return typeofNode.execute(obj).getName();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
index 37c491068901c450a3ca6abee0de184388a5ffaa..04288a4970a4ee6953ef51996511f9d076172ed3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java
@@ -20,7 +20,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.RemoveClassAttributeNode;
-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.RAttributable;
@@ -34,9 +33,9 @@ public abstract class UnClass extends RBuiltinNode {
     private final BranchProfile objectProfile = BranchProfile.create();
     private final BranchProfile shareableProfile = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").allowNull().asAttributable(true, true, true);
+    static {
+        Casts casts = new Casts(UnClass.class);
+        casts.arg("x").asAttributable(true, true, true);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java
index b6b914319a456d10fc634e9251eeede68ade1c4b..56cad49e98b51266daf2922badc316f2ccd52ffd 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unique.java
@@ -34,7 +34,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSet;
 import com.oracle.truffle.r.runtime.Collections.NonRecursiveHashSetDouble;
@@ -70,8 +69,8 @@ public abstract class Unique extends RBuiltinNode {
 
     private final ConditionProfile bigProfile = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Unique.class);
         // these are similar to those in DuplicatedFunctions.java
         casts.arg("x").defaultError(RError.SHOW_CALLER, RError.Message.APPLIES_TO_VECTORS, "unique()").allowNull().mustBe(abstractVectorValue()).asVector();
         // not much more can be done for incomparables as it is either a vector of incomparable
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 4c7d7f36efcf7a969d41eefcf88a8ca622979fc2..67b2bbd51707a4e5a18fa48104f2401aecb7404c 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
@@ -23,7 +23,6 @@ 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;
 import com.oracle.truffle.r.nodes.unary.PrecedenceNode;
@@ -50,8 +49,8 @@ public abstract class Unlist extends RBuiltinNode {
 
     // portions of the algorithm were transcribed from GNU R
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Unlist.class);
         casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
         casts.arg("use.names").asLogicalVector().findFirst(RRuntime.LOGICAL_TRUE).map(toBoolean());
     }
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 1c16ecae624a57b5918ed778d71c05eb0f0fa80e..a9d87f4e4978b08bb04873a4f85121f5632530ef 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
@@ -42,7 +42,6 @@ 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.builtin.base.UpdateAttrNodeGen.InternStringNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -92,14 +91,14 @@ public abstract class UpdateAttr extends RBuiltinNode {
             return interned;
         }
 
-        @Specialization(contains = "internCached")
+        @Specialization(replaces = "internCached")
         protected static String intern(String value) {
             return Utils.intern(value);
         }
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateAttr.class);
         // Note: cannot check 'attributability' easily because atomic values, e.g int, are not
         // RAttributable.
         casts.arg("x"); // disallows null
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 e346d88aad6254f16a80066f34dd1b0064f22e01..b3df6a98a0def6db42cfd3a21ddd4b2798d1ba45 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
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.runtime.RError.Message.ATTRIBUTES_LIST_OR_NULL;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
@@ -37,7 +38,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNames
 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;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen;
@@ -71,12 +71,12 @@ public abstract class UpdateAttributes extends RBuiltinNode {
     @Child private SetRowNamesAttributeNode setRowNamesNode;
     @Child private RemoveAttributeNode removeAttrNode;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateAttributes.class);
         // Note: cannot check 'attributability' easily because atomic values, e.g int, are not
         // RAttributable.
         casts.arg("obj"); // by default disallows RNull
-        casts.arg("value").conf(c -> c.allowNull()).mustBe(instanceOf(RList.class), this, ATTRIBUTES_LIST_OR_NULL);
+        casts.arg("value").mustBe(nullValue().or(instanceOf(RList.class)), ATTRIBUTES_LIST_OR_NULL);
     }
 
     // it's OK for the following two methods to update attributes in-place as the container has been
@@ -214,7 +214,6 @@ public abstract class UpdateAttributes extends RBuiltinNode {
                 } else {
                     setClassNode.execute(res, UpdateAttr.convertClassAttrFromObject(value));
                 }
-                res = result;
             } else if (attrName.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
                 if (setRowNamesNode == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
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 95cb88093e116c5b93305e3e6c69878202d88da6..7fd8850a961d0376793af976ff8af21e38e979f4 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
@@ -23,7 +23,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClass
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNodeGen;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
@@ -51,10 +50,10 @@ public abstract class UpdateClass extends RBuiltinNode {
     @Child private TypeofNode typeof;
     @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateClass.class);
         casts.arg("x"); // disallows null
-        casts.arg("value").allowNull().asStringVector();
+        casts.arg("value").asStringVector();
     }
 
     @Specialization
@@ -73,7 +72,7 @@ public abstract class UpdateClass extends RBuiltinNode {
         return setClassInternal(arg, cachedClassName, cachedMode, getClassNode);
     }
 
-    @Specialization(contains = "setClassCached")
+    @Specialization(replaces = "setClassCached")
     protected Object setClass(RAbstractContainer arg, String className,
                     @Cached("create()") TypeFromModeNode typeFromMode,
                     @Cached("create()") GetClassAttributeNode getClassNode) {
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 d30e638139ad629645041ed73dab870e8b043753..867c09bfd9d94bd70f5967e5081c10ab2e3c58cd 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.object.DynamicObject;
 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.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.builtins.RBuiltin;
@@ -49,10 +48,10 @@ public abstract class UpdateDim extends RBuiltinNode {
 
     @Child private ReuseNonSharedNode reuse = ReuseNonSharedNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateDim.class);
         casts.arg("x"); // disallows null
-        casts.arg("value").allowNull().asIntegerVector().mustBe(notEmpty(), this, LENGTH_ZERO_DIM_INVALID);
+        casts.arg("value").allowNull().asIntegerVector().mustBe(notEmpty(), LENGTH_ZERO_DIM_INVALID);
     }
 
     @Specialization
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 d521f8a0edbac77d286ce14594ef8e9fbfb7db73..439c1b4a24a87890249021686aca040f5b847443 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
@@ -55,6 +55,10 @@ public abstract class UpdateDimNames extends RBuiltinNode {
     @Child private CastStringNode castStringNode;
     @Child private CastToVectorNode castVectorNode;
 
+    static {
+        Casts.noCasts(UpdateDimNames.class);
+    }
+
     private Object castString(Object o) {
         if (castStringNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java
index 67a5eae4cbc6df624c278543a6198e9318c3cd31..38199269d78caf344dda3e5852a7be155b2c1586 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLength.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@ 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.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.RNull;
@@ -43,15 +42,11 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 @RBuiltin(name = "length<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class UpdateLength extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateLength.class);
         // Note: `length<-`(NULL, newLen) really works in GnuR unlike other update builtins
-        // @formatter:off
-        casts.arg("x").conf(c -> c.allowNull()).mustBe(abstractVectorValue(), this, INVALID_UNNAMED_ARGUMENT);
-        casts.arg("value").defaultError(this, INVALID_UNNAMED_VALUE).
-                mustBe(integerValue().or(doubleValue()).or(stringValue())).
-                asIntegerVector().mustBe(singleElement()).findFirst();
-        // @formatter:on
+        casts.arg("x").allowNull().mustBe(abstractVectorValue(), INVALID_UNNAMED_ARGUMENT);
+        casts.arg("value").defaultError(INVALID_UNNAMED_VALUE).mustBe(integerValue().or(doubleValue()).or(stringValue())).asIntegerVector().mustBe(singleElement()).findFirst();
     }
 
     @SuppressWarnings("unused")
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 472dc7388aede531c59cf4a9ac9e43687ebaacab..fd018457e0b7ae7593f0fb9eda653088196bd516 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
@@ -19,7 +19,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 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.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -32,8 +31,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 @RBuiltin(name = "levels<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class UpdateLevels extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(UpdateLevels.class);
         casts.arg("value").allowNull().asVector(false);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
index 134470c264132a4450dd6cff633200d80d78115f..afefd3a53d9906356b15807444a5985e6a550171 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java
@@ -46,6 +46,10 @@ public abstract class UpdateNames extends RBuiltinNode {
 
     @Child private CastStringNode castStringNode;
 
+    static {
+        Casts.noCasts(UpdateNames.class);
+    }
+
     private Object castString(Object o) {
         if (castStringNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
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 02c1ab3e723189351e01281fc7714e35326c9270..0ba6831d05d0ce923b21cda2912c773c0c5c3679 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,10 @@ public abstract class UpdateOldClass extends RBuiltinNode {
     @Child private CastStringNode castStringNode;
     @Child private SetClassAttributeNode setClassAttributeNode = SetClassAttributeNode.create();
 
+    static {
+        Casts.noCasts(UpdateOldClass.class);
+    }
+
     @Specialization(guards = "!isStringVector(className)")
     protected Object setOldClass(RAbstractContainer arg, RAbstractVector className) {
         if (className.getLength() == 0) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
index a78fde5483d585c723197e1b9fdd90967a7b9f0a..9dcc170b841a3627d3d383a9122823f5e6dc15f8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
@@ -6,7 +6,7 @@
  * Copyright (c) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1995-2014, The R Core Team
  * Copyright (c) 2002-2008, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -25,7 +25,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.UpdateSlotNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
@@ -51,14 +50,14 @@ public abstract class UpdateSlot extends RBuiltinNode {
     @CompilationFinal private RFunction checkSlotAssignFunction;
     @Child private ClassHierarchyNode objClassHierarchy;
     @Child private ClassHierarchyNode valClassHierarchy;
-    @Child private UpdateSlotNode updateSlotNode = com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen.create(null, null, null);
+    @Child private UpdateSlotNode updateSlotNode = com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen.create();
     @Child private ReadVariableNode checkAtAssignmentFind = ReadVariableNode.createFunctionLookup(RSyntaxNode.INTERNAL, "checkAtAssignment");
     @Child private CallRFunctionNode checkAtAssignmentCall;
     private final ConditionProfile cached = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(0).allowNull().asAttributable(true, true, true);
+    static {
+        Casts casts = new Casts(UpdateSlot.class);
+        casts.arg(0).asAttributable(true, true, true);
     }
 
     protected String getName(Object nameObj) {
@@ -90,14 +89,21 @@ public abstract class UpdateSlot extends RBuiltinNode {
         if (checkSlotAssignFunction == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             checkSlotAssignFunction = (RFunction) checkAtAssignmentFind.execute(frame);
+        }
+        if (checkAtAssignmentCall == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             checkAtAssignmentCall = insert(CallRFunctionNode.create(checkSlotAssignFunction.getTarget()));
-            assert objClassHierarchy == null && valClassHierarchy == null;
+        }
+        if (objClassHierarchy == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             objClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false));
+        }
+        if (valClassHierarchy == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             valClassHierarchy = insert(ClassHierarchyNodeGen.create(true, false));
-
         }
         RStringVector objClass = objClassHierarchy.execute(object);
-        RStringVector valClass = objClassHierarchy.execute(value);
+        RStringVector valClass = valClassHierarchy.execute(value);
         RFunction currentFunction = (RFunction) checkAtAssignmentFind.execute(frame);
         if (cached.profile(currentFunction == checkSlotAssignFunction)) {
             // TODO: technically, someone could override checkAtAssignment function and access the
@@ -121,7 +127,7 @@ public abstract class UpdateSlot extends RBuiltinNode {
         return updateSlotNode.executeUpdate(object, name, value);
     }
 
-    @Specialization(contains = "updateSlotCached")
+    @Specialization(replaces = "updateSlotCached")
     protected Object updateSlot(VirtualFrame frame, Object object, Object nameObj, Object value) {
         String name = getName(nameObj);
         checkSlotAssign(frame, object, name, value);
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 804b73b66704a390fa5dee5d937b25a7c650b76d..690118997285088d23f31997c41305f015ec98c4 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
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -51,6 +51,10 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
 
     private final BranchProfile errorProfile = BranchProfile.create();
 
+    static {
+        Casts.noCasts(UpdateStorageMode.class);
+    }
+
     @Specialization
     protected Object update(Object x, String value,
                     @Cached("create()") ArrayAttributeNode attrAttrAccess,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
index c6cb92740a5b200d81b1b70d47ac3bee7a5b673a..0211c6ed55c6a46ef7ae1af8074b720bb2ee6427 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,10 @@ public abstract class UpdateSubstr extends RBuiltinNode {
 
     private final BranchProfile everSeenIllegalRange = BranchProfile.create();
 
+    static {
+        Casts.noCasts(UpdateSubstr.class);
+    }
+
     private static boolean rangeOk(String x, int start, int stop) {
         return start <= stop && start > 0 && stop > 0 && start <= x.length() && stop <= x.length();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java
index c1ba6395b156a309c7a5619dd38cdb7cfe8f0a0f..50aa92742d8aacee4305eabf32f687c48a09d668 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Utf8ToInt.java
@@ -29,7 +29,6 @@ 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 @RBuiltin(name = "utf8ToInt", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class Utf8ToInt extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Utf8ToInt.class);
         casts.arg(0, "x").defaultError(RError.SHOW_CALLER, RError.Message.ARG_MUST_BE_CHARACTER_VECTOR_LENGTH_ONE, "x").mustBe(stringValue()).asStringVector().mustBe(notEmpty()).shouldBe(size(1),
                         RError.SHOW_CALLER, RError.Message.ARG_SHOULD_BE_CHARACTER_VECTOR_LENGTH_ONE).findFirst();
     }
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 83f99a9513a2e09bb32b33e7d754e008d0e4af4a..b8d5a7b81f9b56e90c119e76d0dbeefc6017d74d 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,6 @@ 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;
 import com.oracle.truffle.r.nodes.builtin.base.LapplyNodeGen.LapplyInternalNodeGen;
@@ -95,8 +94,8 @@ public abstract class VApply extends RBuiltinNode {
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
     @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(VApply.class);
         casts.arg("X").asVector();
         casts.arg("FUN").mustBe(instanceOf(RFunction.class), RError.SHOW_CALLER, RError.Message.APPLY_NON_FUNCTION);
         // casts.arg("FUN.VALUE").mapIf(anyValue(),
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
index c942eacc8a4a562af2a4749cd517b0b1cdb63e8f..ee217670d4cccdd73e0fec37bba57a8401f459c6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
-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.RType;
@@ -45,8 +44,8 @@ public abstract class Vector extends RBuiltinNode {
 
     @Child private TypeFromModeNode typeFromMode = TypeFromModeNodeGen.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Vector.class);
         casts.arg("mode").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "mode").asStringVector().mustBe(singleElement()).findFirst();
         casts.arg("length").defaultError(RError.SHOW_CALLER, RError.Message.INVALID_ARGUMENT, "length").asIntegerVector().mustBe(singleElement()).findFirst();
     }
@@ -66,7 +65,7 @@ public abstract class Vector extends RBuiltinNode {
         return createType(type, length);
     }
 
-    @Specialization(contains = "vectorCached")
+    @Specialization(replaces = "vectorCached")
     @TruffleBoundary
     protected Object vector(String mode, int length) {
         return createType(modeToType(mode), length);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java
index bfb083d1593de793b7015cbe6c2e6a72882a1d0e..164019046ff4edb35b945d0888af84da8adf7d26 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java
@@ -31,7 +31,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RError;
 import com.oracle.truffle.r.runtime.RErrorHandling;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = "warning", visibility = OFF, kind = INTERNAL, parameterNames = {"call", "immediate", "nobreaks", "message"}, behavior = COMPLEX)
 public abstract class Warning extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Warning.class);
         casts.arg("call").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("immediate").asLogicalVector().findFirst().map(toBoolean());
         casts.arg("nobreaks").asLogicalVector().findFirst().map(toBoolean());
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 14614074f986b56a2698b9eccd9b6a13189b4b8d..1a7797de13201002e0ffbcd5197989a1491c5b01 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@ 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;
 import com.oracle.truffle.r.nodes.builtin.base.WhichFunctionsFactory.WhichMinNodeGen;
@@ -54,8 +53,8 @@ public class WhichFunctions {
     @RBuiltin(name = "which", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
     public abstract static class Which extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Which.class);
             casts.arg("x").mustBe(logicalValue()).asLogicalVector();
         }
 
@@ -111,9 +110,10 @@ public class WhichFunctions {
             this.isMax = isMax;
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            casts.arg(0, "x").allowNull().asDoubleVector(true, false, false);
+        protected static Casts createCasts(Class<? extends WhichMinMax> extCls) {
+            Casts casts = new Casts(extCls);
+            casts.arg(0, "x").asDoubleVector(true, false, false);
+            return casts;
         }
 
         @Specialization
@@ -156,6 +156,11 @@ public class WhichFunctions {
 
     @RBuiltin(name = "which.max", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
     public abstract static class WhichMax extends WhichMinMax {
+
+        static {
+            createCasts(WhichMax.class);
+        }
+
         protected WhichMax() {
             super(true);
         }
@@ -167,6 +172,11 @@ public class WhichFunctions {
 
     @RBuiltin(name = "which.min", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
     public abstract static class WhichMin extends WhichMinMax {
+
+        static {
+            createCasts(WhichMin.class);
+        }
+
         protected WhichMin() {
             super(false);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
index f1bdec68e310da340ff1285a9575361b24c8c0d5..fa52a36dfcb76e8a3c494bfadc59bedee2360544 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,37 +25,80 @@ 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.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.function.visibility.GetVisibilityNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 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.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.nodes.RNode;
+
+final class WithVisibleSpecial extends RNode {
+
+    @Child private RNode delegate;
+    @Child private GetVisibilityNode visibility = GetVisibilityNode.create();
+
+    protected WithVisibleSpecial(RNode delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        Object value = delegate.visibleExecute(frame);
+        if (value == RMissing.instance) {
+            CompilerDirectives.transferToInterpreter();
+            throw RError.error(this, Message.ARGUMENT_MISSING, "x");
+        }
+        return RDataFactory.createList(new Object[]{value, RRuntime.asLogical(visibility.execute(frame))}, WithVisible.LISTNAMES);
+    }
+}
 
 // TODO The base package manual says this is a primitive but GNU R implements it as .Internal.
 // That causes problems as the .Internal adds another layer of visibility setting that
 // gets the wrong result. I believe that the only way to handle it as a .Internal would be to
 // set noEvalArgs and evaluate the argument here and set the visibility explicitly.
-@RBuiltin(name = "withVisible", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX)
+@RBuiltin(name = "withVisible", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX, nonEvalArgs = {0})
 public abstract class WithVisible extends RBuiltinNode {
 
-    private static final RStringVector LISTNAMES = (RStringVector) RDataFactory.createStringVector(new String[]{"value", "visible"}, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent();
+    static final RStringVector LISTNAMES = (RStringVector) RDataFactory.createStringVector(new String[]{"value", "visible"}, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x");
+    public static RNode createSpecial(@SuppressWarnings("unused") ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) {
+        return arguments.length == 1 ? new WithVisibleSpecial(arguments[0]) : null;
+    }
+
+    @Specialization
+    protected RList withVisible(VirtualFrame frame, RPromise x,
+                    @Cached("create()") GetVisibilityNode visibility,
+                    @Cached("new()") PromiseHelperNode promiseHelper) {
+        if (x.isEvaluated()) {
+            return RDataFactory.createList(new Object[]{x.getValue(), RRuntime.LOGICAL_TRUE}, LISTNAMES);
+        }
+        Object value = promiseHelper.evaluate(frame, x);
+        if (value == RMissing.instance) {
+            CompilerDirectives.transferToInterpreter();
+            throw RError.error(this, Message.ARGUMENT_MISSING, "x");
+        }
+        return RDataFactory.createList(new Object[]{value, RRuntime.asLogical(visibility.execute(frame))}, LISTNAMES);
+    }
+
+    static {
+        Casts.noCasts(WithVisible.class);
     }
 
     @Specialization
-    protected RList withVisible(VirtualFrame frame, Object x,
-                    @Cached("create()") GetVisibilityNode visibility) {
-        Object[] data = new Object[]{x, RRuntime.asLogical(visibility.execute(frame))};
-        return RDataFactory.createList(data, LISTNAMES);
+    protected RList withVisible(@SuppressWarnings("unused") RMissing x) {
+        CompilerDirectives.transferToInterpreter();
+        throw RError.error(this, Message.ARGUMENT_MISSING, "x");
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
index 1c8a3656ce594af08fe7f5997c7a2bc988764cb0..7d2c7fdfc68f94376451a5b07c2614759a4eb999 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,10 @@ public abstract class Xtfrm extends RBuiltinNode {
 
     @Child private GetFunctions.Get getNode;
 
+    static {
+        Casts.noCasts(Xtfrm.class);
+    }
+
     @Specialization
     protected Object xtfrm(VirtualFrame frame, Object x,
                     @Cached("createBinaryProfile()") ConditionProfile createProfile) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java
index 677dda88272d4a71965c93d95ecc94e5cd6c0368..3239623be3b4baca0f6f05e25b6d7f349f156f3e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IsElementFastPath.java
@@ -81,7 +81,7 @@ public abstract class IsElementFastPath extends RFastPathNode {
         return RRuntime.asLogical(profile.profile(element >= set.getStart() && element <= set.getEnd()));
     }
 
-    @Specialization(contains = "isElementOneSequence", guards = "el.getLength() == 1")
+    @Specialization(replaces = "isElementOneSequence", guards = "el.getLength() == 1")
     protected Byte iselementOne(RAbstractDoubleVector el, RAbstractIntVector set,
                     @Cached("create()") NACheck na,
                     @Cached("create()") BranchProfile trueProfile,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/VectorFastPaths.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/VectorFastPaths.java
index 102ef1d27c37093bf6c1f0397cb15de855d964bb..4e63574d6c4a52e2b7269999505d4f6186e3eb3b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/VectorFastPaths.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/VectorFastPaths.java
@@ -25,7 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.base.fastpaths;
 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.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -43,20 +43,18 @@ public abstract class VectorFastPaths {
 
         @Specialization
         protected RAbstractIntVector get(int length,
-                        @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
-            if (emptyProfile.profile(length == 0)) {
-                return RDataFactory.createIntVector(0);
-            } else if (length > 0) {
-                return RDataFactory.createIntSequence(0, 0, length);
+                        @Cached("create()") VectorLengthProfile profile) {
+            if (length > 0) {
+                return RDataFactory.createIntVector(profile.profile(length));
             }
             return null;
         }
 
         @Specialization
         protected RAbstractIntVector get(double length,
-                        @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
+                        @Cached("create()") VectorLengthProfile profile) {
             if (!Double.isNaN(length)) {
-                return get((int) length, emptyProfile);
+                return get((int) length, profile);
             }
             return null;
         }
@@ -77,20 +75,18 @@ public abstract class VectorFastPaths {
 
         @Specialization
         protected RAbstractDoubleVector get(int length,
-                        @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
-            if (emptyProfile.profile(length == 0)) {
-                return RDataFactory.createDoubleVector(0);
-            } else if (length > 0) {
-                return RDataFactory.createDoubleSequence(0, 0, length);
+                        @Cached("create()") VectorLengthProfile profile) {
+            if (length > 0) {
+                return RDataFactory.createDoubleVector(profile.profile(length));
             }
             return null;
         }
 
         @Specialization
         protected RAbstractDoubleVector get(double length,
-                        @Cached("createBinaryProfile()") ConditionProfile emptyProfile) {
+                        @Cached("create()") VectorLengthProfile profile) {
             if (!Double.isNaN(length)) {
-                return get((int) length, emptyProfile);
+                return get((int) length, profile);
             }
             return null;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java
index 5b13b78fd41c85a1360b40ba0b6770479ced4f90..4f9d28cfb20ff21248fc873b73113f5b7a46baf5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CairoProps.java
@@ -5,22 +5,21 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
 package com.oracle.truffle.r.nodes.builtin.base.foreign;
 
 import com.oracle.truffle.api.dsl.Specialization;
-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.model.RAbstractIntVector;
 
 public abstract class CairoProps extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(CairoProps.class);
         casts.arg(0).asIntegerVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index a268a72ea9b9f4677852e5ad457217a8234a5989..1eae28232995f9b72a0ec43819f80db65a246506 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -202,7 +202,7 @@ public class CallAndExternalFunctions {
     }
 
     abstract static class CallRFFIAdapter extends LookupAdapter {
-        @Child CallRFFI.CallRFFINode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode();
+        @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
     }
 
     /**
@@ -226,6 +226,10 @@ public class CallAndExternalFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
+        static {
+            Casts.noCasts(DotCall.class);
+        }
+
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RMissing.instance};
@@ -621,6 +625,16 @@ public class CallAndExternalFunctions {
                 case "sockwrite":
                     return new UnimplementedExternal(name);
 
+                // parallel
+                case "mc_is_child":
+                    return MCIsChildNodeGen.create();
+                default:
+                    return FastROptions.UseInternalGraphics.getBooleanValue() ? lookupGraphicsBuiltin(name) : null;
+            }
+        }
+
+        private static RExternalBuiltinNode lookupGraphicsBuiltin(String name) {
+            switch (name) {
                 // grDevices
                 case "cairoProps":
                     return CairoPropsNodeGen.create();
@@ -632,10 +646,6 @@ public class CallAndExternalFunctions {
                     return InitGridNodeGen.create();
                 case "L_validUnits":
                     return ValidUnitsNodeGen.create();
-
-                // parallel
-                case "mc_is_child":
-                    return MCIsChildNodeGen.create();
                 default:
                     return null;
             }
@@ -661,7 +671,7 @@ public class CallAndExternalFunctions {
         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());
+            return callRFFINode.execute(nativeCallInfo, args.getArguments());
         }
 
         /**
@@ -669,10 +679,10 @@ public class CallAndExternalFunctions {
          * such cases there is this generic version.
          */
         @SuppressWarnings("unused")
-        @Specialization(contains = "callNamedFunction")
+        @Specialization(replaces = "callNamedFunction")
         protected Object callNamedFunctionGeneric(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName) {
             NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
-            return callRFFINode.invokeCall(nativeCallInfo, args.getArguments());
+            return callRFFINode.execute(nativeCallInfo, args.getArguments());
         }
 
         /**
@@ -680,8 +690,9 @@ public class CallAndExternalFunctions {
          */
         @Specialization
         protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
-                        @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns) {
-            return callNamedFunctionWithPackage(symbol, args, null, rns);
+                        @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            return callNamedFunctionWithPackage(symbol, args, null, rns, findSymbolNode);
         }
 
         /**
@@ -690,13 +701,14 @@ public class CallAndExternalFunctions {
          */
         @Specialization
         protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName,
-                        @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns) {
-            DLL.SymbolHandle func = DLL.findSymbol(symbol, packageName, rns);
+                        @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            DLL.SymbolHandle func = findSymbolNode.execute(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "Call", packageName);
             }
-            return callRFFINode.invokeCall(new NativeCallInfo(symbol, func, rns.getDllInfo()), args.getArguments());
+            return callRFFINode.execute(new NativeCallInfo(symbol, func, rns.getDllInfo()), args.getArguments());
         }
 
         @SuppressWarnings("unused")
@@ -715,6 +727,10 @@ public class CallAndExternalFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
+        static {
+            Casts.noCasts(DotExternal.class);
+        }
+
         @Override
         @TruffleBoundary
         protected RExternalBuiltinNode lookupBuiltin(RList f) {
@@ -724,7 +740,7 @@ public class CallAndExternalFunctions {
                     case "PDF":
                         return new DevicesCCalls.C_PDF();
                     case "devoff":
-                        return new DevicesCCalls.C_DevOff();
+                        return DevicesCCalls.C_DevOff.create();
                     case "devcur":
                         return new DevicesCCalls.C_DevCur();
                 }
@@ -778,25 +794,27 @@ public class CallAndExternalFunctions {
                         @Cached("symbol") RList cached,
                         @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
-            return callRFFINode.invokeCall(nativeCallInfo, new Object[]{list});
+            return callRFFINode.execute(nativeCallInfo, new Object[]{list});
         }
 
         @Specialization
-        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName, // )
-                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
-            return callNamedFunctionWithPackage(symbol, args, null, rns);
+        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            return callNamedFunctionWithPackage(symbol, args, null, rns, findSymbolNode);
         }
 
         @Specialization
         protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName,
-                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
-            DLL.SymbolHandle func = DLL.findSymbol(symbol, packageName, rns);
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            DLL.SymbolHandle func = findSymbolNode.execute(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "External", packageName);
             }
             Object list = encodeArgumentPairList(args, symbol);
-            return callRFFINode.invokeCall(new NativeCallInfo(symbol, func, rns.getDllInfo()), new Object[]{list});
+            return callRFFINode.execute(new NativeCallInfo(symbol, func, rns.getDllInfo()), new Object[]{list});
         }
 
         @Fallback
@@ -811,6 +829,10 @@ public class CallAndExternalFunctions {
         private static final Object OP = "op";
         private static final Object RHO = "rho";
 
+        static {
+            Casts.noCasts(DotExternal2.class);
+        }
+
         private final BranchProfile errorProfile = BranchProfile.create();
 
         @Override
@@ -854,26 +876,28 @@ public class CallAndExternalFunctions {
                         @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
             // TODO: provide proper values for the CALL, OP and RHO parameters
-            return callRFFINode.invokeCall(nativeCallInfo, new Object[]{CALL, OP, list, RHO});
+            return callRFFINode.execute(nativeCallInfo, new Object[]{CALL, OP, list, RHO});
         }
 
         @Specialization
-        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName, // )
-                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
-            return callNamedFunctionWithPackage(symbol, args, null, rns);
+        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            return callNamedFunctionWithPackage(symbol, args, null, rns, findSymbolNode);
         }
 
         @Specialization
         protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName,
-                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns) {
-            DLL.SymbolHandle func = DLL.findSymbol(symbol, packageName, rns);
+                        @Cached("createRegisteredNativeSymbol(ExternalNST)") DLL.RegisteredNativeSymbol rns,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            DLL.SymbolHandle func = findSymbolNode.execute(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "External2", packageName);
             }
             Object list = encodeArgumentPairList(args, symbol);
             // TODO: provide proper values for the CALL, OP and RHO parameters
-            return callRFFINode.invokeCall(new NativeCallInfo(symbol, func, rns.getDllInfo()), new Object[]{CALL, OP, list, RHO});
+            return callRFFINode.execute(new NativeCallInfo(symbol, func, rns.getDllInfo()), new Object[]{CALL, OP, list, RHO});
         }
 
         @Fallback
@@ -887,6 +911,10 @@ public class CallAndExternalFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
+        static {
+            Casts.noCasts(DotExternalGraphics.class);
+        }
+
         @Override
         @TruffleBoundary
         protected RExternalBuiltinNode lookupBuiltin(RList f) {
@@ -913,24 +941,26 @@ public class CallAndExternalFunctions {
         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 callRFFINode.invokeCall(nativeCallInfo, new Object[]{list});
+            return callRFFINode.execute(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 name, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            return callNamedFunctionWithPackage(name, args, null, findSymbolNode);
         }
 
         @Specialization
-        protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
+        protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.External, null, null);
-            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
+            DLL.SymbolHandle func = findSymbolNode.execute(name, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
             Object list = encodeArgumentPairList(args, name);
-            return callRFFINode.invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{list});
+            return callRFFINode.execute(new NativeCallInfo(name, func, rns.getDllInfo()), new Object[]{list});
         }
 
         @Fallback
@@ -944,6 +974,10 @@ public class CallAndExternalFunctions {
 
         private final BranchProfile errorProfile = BranchProfile.create();
 
+        static {
+            Casts.noCasts(DotCallGraphics.class);
+        }
+
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RMissing.instance};
@@ -969,24 +1003,26 @@ public class CallAndExternalFunctions {
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
             NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
-            return callRFFINode.invokeCall(nativeCallInfo, args.getArguments());
+            return callRFFINode.execute(nativeCallInfo, args.getArguments());
         }
 
         @Specialization
-        protected Object callNamedFunction(String name, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
-            return callNamedFunctionWithPackage(name, args, null);
+        protected Object callNamedFunction(String name, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
+            return callNamedFunctionWithPackage(name, args, null, findSymbolNode);
         }
 
         @Specialization
         @TruffleBoundary
-        protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName) {
+        protected Object callNamedFunctionWithPackage(String name, RArgsValuesAndNames args, String packageName,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Call, null, null);
-            DLL.SymbolHandle func = DLL.findSymbol(name, packageName, rns);
+            DLL.SymbolHandle func = findSymbolNode.execute(name, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 errorProfile.enter();
                 throw RError.error(this, RError.Message.C_SYMBOL_NOT_IN_TABLE, name);
             }
-            return callRFFINode.invokeCall(new NativeCallInfo(name, func, rns.getDllInfo()), args.getArguments());
+            return callRFFINode.execute(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/Dqrcf.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Dqrcf.java
index 3ca0f0c97d0173a30490c3c5cdd8b0bf225426ec..d10efffa16e25c225bdecc3541acd60262ca89f1 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
@@ -5,16 +5,18 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
 package com.oracle.truffle.r.nodes.builtin.base.foreign;
 
+import com.oracle.truffle.api.dsl.Specialization;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -24,40 +26,43 @@ 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 {
+public abstract class Dqrcf extends RExternalBuiltinNode.Arg8 {
     @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);
 
-    @Override
-    public RList call(RArgsValuesAndNames args) {
-        Object[] argValues = args.getArguments();
+    static {
+        Casts casts = new Casts(Dqrcf.class);
+        casts.arg(0).mustBe(doubleValue()).asDoubleVector();
+        casts.arg(1).mustBe(integerValue()).asIntegerVector().findFirst();
+        casts.arg(2).mustBe(integerValue()).asIntegerVector().findFirst();
+        casts.arg(3).mustBe(doubleValue()).asDoubleVector();
+        casts.arg(4).mustBe(doubleValue()).asDoubleVector();
+        casts.arg(5).mustBe(integerValue()).asIntegerVector().findFirst();
+        casts.arg(6).mustBe(doubleValue()).asDoubleVector();
+        casts.arg(7).mustBe(integerValue()).asIntegerVector();
+    }
+
+    @Specialization
+    public RList dqrcf(RAbstractDoubleVector xVec, int nx, int k, RAbstractDoubleVector qrauxVec, RAbstractDoubleVector yVec, int ny, RAbstractDoubleVector bVec, RAbstractIntVector infoVec) {
         try {
-            RAbstractDoubleVector xVec = (RAbstractDoubleVector) argValues[0];
-            int n = argValues[1] instanceof Integer ? (int) argValues[1] : ((RAbstractIntVector) argValues[1]).getDataAt(0);
-            RAbstractIntVector k = (RAbstractIntVector) argValues[2];
-            RAbstractDoubleVector qrauxVec = (RAbstractDoubleVector) argValues[3];
-            RAbstractDoubleVector yVec = (RAbstractDoubleVector) argValues[4];
-            int ny = argValues[5] instanceof Integer ? (int) argValues[5] : ((RAbstractIntVector) argValues[5]).getDataAt(0);
-            RAbstractDoubleVector bVec = (RAbstractDoubleVector) argValues[6];
-            RAbstractIntVector infoVec = (RAbstractIntVector) argValues[7];
             double[] x = xVec.materialize().getDataTemp();
             double[] qraux = qrauxVec.materialize().getDataTemp();
             double[] y = yVec.materialize().getDataTemp();
             double[] b = bVec.materialize().getDataTemp();
             int[] info = infoVec.materialize().getDataTemp();
-            rApplRFFINode.dqrcf(x, n, k.getDataAt(0), qraux, y, ny, b, info);
+            rApplRFFINode.dqrcf(x, nx, k, qraux, y, ny, b, info);
             RDoubleVector coef = RDataFactory.createDoubleVector(b, RDataFactory.COMPLETE_VECTOR);
             coef.copyAttributesFrom(bVec);
             // @formatter:off
             Object[] data = new Object[]{
                         RDataFactory.createDoubleVector(x, RDataFactory.COMPLETE_VECTOR),
-                        argValues[1],
-                        k.copy(),
+                        nx,
+                        k,
                         RDataFactory.createDoubleVector(qraux, RDataFactory.COMPLETE_VECTOR),
                         RDataFactory.createDoubleVector(y, RDataFactory.COMPLETE_VECTOR),
-                        argValues[5],
+                        ny,
                         coef,
                         RDataFactory.createIntVector(info, 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 e63b42dd1195018bf6b83324ff0ca72ef2dcdfb1..a188007010dd4331fb089dc8b1b4600b7426b041 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
@@ -5,17 +5,18 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
 package com.oracle.truffle.r.nodes.builtin.base.foreign;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
+import com.oracle.truffle.api.dsl.Specialization;
 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;
-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.RStringVector;
@@ -24,46 +25,49 @@ 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 {
+public abstract class Dqrdc2 extends RExternalBuiltinNode.Arg9 {
     @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);
 
+    public static Dqrdc2 create() {
+        return Dqrdc2NodeGen.create();
+    }
+
     @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create();
 
-    @Override
-    public RList call(RArgsValuesAndNames args) {
-        Object[] argValues = args.getArguments();
-        try {
-            RAbstractDoubleVector xVec = (RAbstractDoubleVector) argValues[0];
-            int ldx = argValues[1] instanceof Integer ? (int) argValues[1] : ((RAbstractIntVector) argValues[1]).getDataAt(0);
-            int n = argValues[2] instanceof Integer ? (int) argValues[2] : ((RAbstractIntVector) argValues[2]).getDataAt(0);
-            int p = argValues[3] instanceof Integer ? (int) argValues[3] : ((RAbstractIntVector) argValues[3]).getDataAt(0);
-            double tol = argValues[4] instanceof Double ? (double) argValues[4] : ((RAbstractDoubleVector) argValues[4]).getDataAt(0);
-            RAbstractIntVector rankVec = (RAbstractIntVector) argValues[5];
-            RAbstractDoubleVector qrauxVec = (RAbstractDoubleVector) argValues[6];
-            RAbstractIntVector pivotVec = (RAbstractIntVector) argValues[7];
-            RAbstractDoubleVector workVec = (RAbstractDoubleVector) argValues[8];
-            double[] x = xVec.materialize().getDataTemp();
-            int[] rank = rankVec.materialize().getDataTemp();
-            double[] qraux = qrauxVec.materialize().getDataTemp();
-            int[] pivot = pivotVec.materialize().getDataTemp();
-            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, getDimNode.getDimensions(xVec)),
-                        argValues[1], argValues[2], argValues[3], argValues[4],
-                        RDataFactory.createIntVector(rank, RDataFactory.COMPLETE_VECTOR),
-                        RDataFactory.createDoubleVector(qraux, RDataFactory.COMPLETE_VECTOR),
-                        RDataFactory.createIntVector(pivot, RDataFactory.COMPLETE_VECTOR),
-                        argValues[8]
-            };
-            // @formatter:on
-            return RDataFactory.createList(data, DQRDC2_NAMES);
-        } catch (ClassCastException | ArrayIndexOutOfBoundsException ex) {
-            errorProfile.enter();
-            throw RError.error(this, RError.Message.INCORRECT_ARG, "dqrdc2");
-        }
+    static {
+        Casts casts = new Casts(Dqrdc2.class);
+        casts.arg(0, "xVec").mustBe(doubleValue()).asDoubleVector();
+        casts.arg(1, "ldx").mustBe(integerValue()).asIntegerVector().findFirst();
+        casts.arg(2, "n").mustBe(integerValue()).asIntegerVector().findFirst();
+        casts.arg(3, "p").mustBe(integerValue()).asIntegerVector().findFirst();
+        casts.arg(4, "tol").mustBe(doubleValue()).asDoubleVector().findFirst();
+        casts.arg(5, "rankVec").mustBe(integerValue()).asIntegerVector();
+        casts.arg(6, "qrauxVec").mustBe(doubleValue()).asDoubleVector();
+        casts.arg(7, "pivotVec").mustBe(integerValue()).asIntegerVector();
+        casts.arg(8, "workVec").mustBe(doubleValue()).asDoubleVector();
+    }
+
+    @Specialization
+    public RList dqrdc2(RAbstractDoubleVector xVec, int ldx, int n, int p, double tol, RAbstractIntVector rankVec, RAbstractDoubleVector qrauxVec, RAbstractIntVector pivotVec,
+                    RAbstractDoubleVector workVec) {
+        double[] x = xVec.materialize().getDataTemp();
+        int[] rank = rankVec.materialize().getDataTemp();
+        double[] qraux = qrauxVec.materialize().getDataTemp();
+        int[] pivot = pivotVec.materialize().getDataTemp();
+        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, getDimNode.getDimensions(xVec)),
+                    ldx, n, p, tol,
+                    RDataFactory.createIntVector(rank, RDataFactory.COMPLETE_VECTOR),
+                    RDataFactory.createDoubleVector(qraux, RDataFactory.COMPLETE_VECTOR),
+                    RDataFactory.createIntVector(pivot, RDataFactory.COMPLETE_VECTOR),
+                    workVec
+        };
+        // @formatter:on
+        return RDataFactory.createList(data, DQRDC2_NAMES);
     }
 }
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 e28bccf67dcab325f38d2b4a2abaa50decd19b15..aeb884a6112ddfb01ba9f6c767fd03a5ae12f1e5 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
@@ -15,23 +15,20 @@ 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;
 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) {
+    static {
+        Casts casts = new Casts(Fft.class);
         casts.arg(0).mustNotBeNull().asComplexVector(false, true, false);
         casts.arg(1).mustNotBeNull().asLogicalVector().findFirst().map(Predef.toBoolean());
     }
@@ -39,7 +36,9 @@ 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,
-                    @Cached("create()") GetDimAttributeNode getDimNode) {
+                    @Cached("create()") GetDimAttributeNode getDimNode,
+                    @Cached("create()") StatsRFFI.FactorNode factorNode,
+                    @Cached("create()") StatsRFFI.WorkNode workNode) {
         double[] z = zVec.materialize().getDataTemp();
         int inv = inverse ? 2 : -2;
         int[] d = getDimNode.getDimensions(zVec);
@@ -50,14 +49,14 @@ public abstract class Fft extends RExternalBuiltinNode.Arg2 {
             int[] maxp = new int[1];
             if (noDims.profile(d == null)) {
                 int n = zVec.getLength();
-                fftNode.executeFactor(n, maxf, maxp);
+                factorNode.execute(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 = fftNode.executeWork(z, 1, n, 1, inv, work, iwork);
+                retCode = workNode.execute(z, 1, n, 1, inv, work, iwork);
             } else {
                 int maxmaxf = 1;
                 int maxmaxp = 1;
@@ -65,7 +64,7 @@ public abstract class Fft extends RExternalBuiltinNode.Arg2 {
                 /* do whole loop just for error checking and maxmax[fp] .. */
                 for (int i = 0; i < ndims; i++) {
                     if (d[i] > 1) {
-                        fftNode.executeFactor(d[i], maxf, maxp);
+                        factorNode.execute(d[i], maxf, maxp);
                         if (maxf[0] == 0) {
                             errorProfile.enter();
                             throw RError.error(this, RError.Message.FFT_FACTORIZATION);
@@ -88,8 +87,8 @@ public abstract class Fft extends RExternalBuiltinNode.Arg2 {
                         nspn *= n;
                         n = d[i];
                         nseg /= n;
-                        fftNode.executeFactor(n, maxf, maxp);
-                        fftNode.executeWork(z, nseg, n, nspn, inv, work, iwork);
+                        factorNode.execute(n, maxf, maxp);
+                        workNode.execute(z, nseg, n, nspn, inv, work, iwork);
                     }
                 }
             }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java
index 676a0d0deea140b9bf66bd076b2df41b1cd3d26e..6e7ef5004d895fc25a9935310cc6dbffed4193a1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/Flushconsole.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,6 +17,10 @@ import com.oracle.truffle.r.runtime.data.RNull;
 
 public final class Flushconsole extends RExternalBuiltinNode {
 
+    static {
+        Casts.noCasts(Flushconsole.class);
+    }
+
     @Override
     public RNull call(RArgsValuesAndNames args) {
         return RNull.instance;
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
index 893f18f7ad5c6e35f5d6153b52befa2f835834b5..d3d6625fa2359679f28b4d1dc87917ff036161e7 100644
--- 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
@@ -62,7 +62,7 @@ public class FortranAndCFunctions {
         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();
+        @Child private CRFFI.InvokeCNode invokeCNode = RFFIFactory.getRFFI().getCRFFI().createInvokeCNode();
 
         @Override
         public Object[] getDefaultParameterValues() {
@@ -110,7 +110,7 @@ public class FortranAndCFunctions {
                     throw RError.error(node, RError.Message.UNIMPLEMENTED_ARG_TYPE, i + 1);
                 }
             }
-            cRFFINode.invoke(nativeCallInfo, nativeArgs);
+            invokeCNode.execute(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];
@@ -192,14 +192,18 @@ public class FortranAndCFunctions {
     @RBuiltin(name = ".Fortran", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
     public abstract static class Fortran extends CRFFIAdapter {
 
+        static {
+            Casts.noCasts(Fortran.class);
+        }
+
         @Override
         @TruffleBoundary
         protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
             switch (lookupName(symbol)) {
                 case "dqrdc2":
-                    return new Dqrdc2();
+                    return Dqrdc2.create();
                 case "dqrcf":
-                    return new Dqrcf();
+                    return DqrcfNodeGen.create();
                 default:
                     return null;
             }
@@ -222,10 +226,11 @@ public class FortranAndCFunctions {
 
         @Specialization
         protected RList c(RAbstractStringVector symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, @SuppressWarnings("unused") RMissing encoding,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode,
                         @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);
+            DLL.SymbolHandle func = findSymbolNode.execute(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);
@@ -243,6 +248,10 @@ public class FortranAndCFunctions {
     @RBuiltin(name = ".C", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
     public abstract static class DotC extends CRFFIAdapter {
 
+        static {
+            Casts.noCasts(DotC.class);
+        }
+
         @Override
         @TruffleBoundary
         protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
@@ -259,6 +268,7 @@ public class FortranAndCFunctions {
         @SuppressWarnings("unused")
         @Specialization
         protected RList c(RAbstractStringVector symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, RMissing encoding,
+                        @Cached("create()") DLL.RFindSymbolNode findSymbolNode,
                         @Cached("create()") BranchProfile errorProfile) {
             String libName = null;
             if (!(rPackage instanceof RMissing)) {
@@ -269,7 +279,7 @@ public class FortranAndCFunctions {
                 }
             }
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.C, null, null);
-            DLL.SymbolHandle func = DLL.findSymbol(symbol.getDataAt(0), libName, rns);
+            DLL.SymbolHandle func = findSymbolNode.execute(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);
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
index c2ffbc4f9e5561b92eb6100884eeb58e4a5866ac..e71e6060a33c7377ab27cadcb99ab23d95b9043a 100644
--- 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
@@ -74,6 +74,10 @@ abstract class LookupAdapter extends RBuiltinNode {
     protected static class UnimplementedExternal extends RExternalBuiltinNode {
         private final String name;
 
+        static {
+            Casts.noCasts(UnimplementedExternal.class);
+        }
+
         public UnimplementedExternal(String name) {
             this.name = name;
         }
@@ -151,15 +155,15 @@ abstract class LookupAdapter extends RBuiltinNode {
         protected Object extractNativeCallInfo(VirtualFrame frame, RList symbol) {
             if (nameExtract == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                nameExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+                nameExtract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true));
             }
             if (addressExtract == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                addressExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+                addressExtract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true));
             }
             if (packageExtract == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+                packageExtract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true));
             }
             String name = RRuntime.asString(nameExtract.applyAccessField(frame, symbol, "name"));
             SymbolHandle address = ((RExternalPtr) addressExtract.applyAccessField(frame, symbol, "address")).getAddr();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java
index c0a8cbaffaee764c767a817b3f193b827affcfca..01f7905dfbab5f5baa4e2b64b5815845e64cfc32 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/MakeQuartzDefault.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -17,6 +17,10 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 
 public final class MakeQuartzDefault extends RExternalBuiltinNode {
 
+    static {
+        Casts.noCasts(MakeQuartzDefault.class);
+    }
+
     @Override
     public Object call(RArgsValuesAndNames args) {
         return RRuntime.LOGICAL_FALSE;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java
index e0c3cec0f8410e73c9d344af9bcbf2b0bc366971..71b34f14650b59a0124a88b485e15c153e94a17f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ReadTableHead.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -15,7 +15,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -25,8 +24,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class ReadTableHead extends RExternalBuiltinNode.Arg7 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(ReadTableHead.class);
         casts.arg(0).defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         casts.arg(1).mustNotBeNull().asIntegerVector().findFirst();
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
index 60e548ee53dfb157b334cbc75ffcf27e50d7e150..53cbadf9d42d75f9cc5fa5956c6511d145ff22f8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java
@@ -18,7 +18,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.printer.ComplexVectorPrinter;
@@ -50,8 +49,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public abstract class WriteTable extends RExternalBuiltinNode.Arg11 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(WriteTable.class);
         // file
         casts.arg(1).defaultError(Message.INVALID_CONNECTION).mustNotBeNull().asIntegerVector().findFirst();
         // nrows
@@ -61,13 +60,13 @@ public abstract class WriteTable extends RExternalBuiltinNode.Arg11 {
         // rnames
         casts.arg(4).allowNull().mustBe(stringValue()).asStringVector();
         // sep
-        casts.arg(5).mustNotBeNull().mustBe(stringValue()).asStringVector().findFirst();
+        casts.arg(5).mustBe(stringValue()).asStringVector().findFirst();
         // eol
-        casts.arg(6).mustNotBeNull().mustBe(stringValue()).asStringVector().findFirst();
+        casts.arg(6).mustBe(stringValue()).asStringVector().findFirst();
         // na
-        casts.arg(7).mustNotBeNull().mustBe(stringValue()).asStringVector().findFirst();
+        casts.arg(7).mustBe(stringValue()).asStringVector().findFirst();
         // dec
-        casts.arg(8).mustNotBeNull().mustBe(stringValue()).asStringVector().findFirst().mustBe(Predef.length(1), RError.Message.GENERIC, "'dec' must be a single character");
+        casts.arg(8).mustBe(stringValue()).asStringVector().findFirst().mustBe(Predef.length(1), RError.Message.GENERIC, "'dec' must be a single character");
         // quote
         casts.arg(9).mustNotBeNull().asIntegerVector();
         // qmethod
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 9a435cdd16cbe7f67f6ab016b157a05ddf5f9ab0..e41593722b78fb9fbe863d0bbae378ca83e80edf 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
@@ -70,7 +69,7 @@ abstract class AccessFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
         return extractListElement.execute(list, index);
     }
 
-    @Specialization(contains = "doList", guards = {"isSimpleList(list)", "list.getNames() != null"})
+    @Specialization(replaces = "doList", guards = {"isSimpleList(list)", "list.getNames() != null"})
     public Object doListDynamic(RList list, String field) {
         int index = getIndex(getNamesNode.getNames(list), field);
         if (index == -1) {
@@ -90,13 +89,13 @@ abstract class AccessFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
 @TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 public abstract class AccessField extends RBuiltinNode {
 
-    @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+    @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.FIELD_SUBSCRIPT, true);
 
     private final ConditionProfile invalidAtomicVector = ConditionProfile.createBinaryProfile();
     private final BranchProfile error = BranchProfile.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(AccessField.class);
         casts.arg(1).defaultError(Message.INVALID_SUBSCRIPT_TYPE, RType.Language.getName()).mustBe(stringValue()).asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltin.java
index 0af31a87568f97662b715ea3ea2cc3bd3984b762..48c2028bde2df0d1f58841ded91aece5ecb2a9b8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "<-", visibility = RVisibility.OFF, kind = PRIMITIVE, parameterNames = {"x", "i"}, behavior = RBehavior.MODIFIES_FRAME)
 public abstract class AssignBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x, Object i) {
+    protected Object doIt(@SuppressWarnings("unused") Object x, @SuppressWarnings("unused") Object i) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltinEq.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltinEq.java
index 95885e8a30e140035c60acd02d82af57ec80a8a7..26185da3e6973e1a2e97548cfe9a8d98b59b2982 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltinEq.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignBuiltinEq.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "=", visibility = RVisibility.OFF, kind = PRIMITIVE, parameterNames = {"x", "i"}, behavior = RBehavior.MODIFIES_FRAME)
 public abstract class AssignBuiltinEq extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x, Object i) {
+    protected Object doIt(@SuppressWarnings("unused") Object x, @SuppressWarnings("unused") Object i) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignOuterBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignOuterBuiltin.java
index 3e77803457c58a3b68035474e52d27c0054f6e49..fd990f8ec409867259267a6d9ac4d2a7163a0c7a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignOuterBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AssignOuterBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "<<-", visibility = RVisibility.OFF, kind = PRIMITIVE, parameterNames = {"x", "i"}, behavior = COMPLEX)
 public abstract class AssignOuterBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x, Object i) {
+    protected Object doIt(@SuppressWarnings("unused") Object x, @SuppressWarnings("unused") Object i) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BraceBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BraceBuiltin.java
index 8f16de33a5ca16e9e182d07f0d22825ae99cfc06..80ff6820346e2e7cf5ccc26d36f2b78fec70d676 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BraceBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BraceBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "{", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
 public abstract class BraceBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x) {
+    protected Object doIt(@SuppressWarnings("unused") Object x) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BreakBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BreakBuiltin.java
index 01f7da077754737f1d0db909b9d2c5868026fe5a..b4dea21f7484e6fae3bc9130ff148ae5fd745b07 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BreakBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/BreakBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,9 +32,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "break", kind = PRIMITIVE, parameterNames = {"x"}, behavior = COMPLEX)
 public abstract class BreakBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x) {
+    protected Object doIt(@SuppressWarnings("unused") Object x) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ForBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ForBuiltin.java
index 3f73a57513005f5fba456f7c5cb8bd7c86c65b4e..562c7be2c0d3904260739861cba1ce073d19f457 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ForBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ForBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "for", visibility = OFF, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
 public abstract class ForBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x) {
+    protected Object doIt(@SuppressWarnings("unused") Object x) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java
index 8cff9b6229b75dfb53bc83565fa8ac1c8a4762ad..b1ebcae60c1da66b990b936a3fddde3bd9011961 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,9 +32,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = READS_FRAME)
 public abstract class FunctionBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x) {
+    protected Object doIt(@SuppressWarnings("unused") Object x) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/IfBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/IfBuiltin.java
index fa86a26fed9099b43264b70447ccf4a05b2e9b8a..9c6ebc6058fd1b7a062eeb3146afb6e7194e5c05 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/IfBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/IfBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "if", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
 public abstract class IfBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x) {
+    protected Object doIt(@SuppressWarnings("unused") Object x) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/NextBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/NextBuiltin.java
index b26ceb62690aa9016ec6dde9c9380820d2a511ab..d83ea3512951829db7d2f948c5f530244cf43a32 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/NextBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/NextBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,9 +32,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "next", kind = PRIMITIVE, parameterNames = {"x"}, behavior = COMPLEX)
 public abstract class NextBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x) {
+    protected Object doIt(@SuppressWarnings("unused") Object x) {
         throw RInternalError.unimplemented();
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java
index a8655bf30d7bebc0b629f7f17af748376f1d30a5..08d6f1a6243c1359527a535f4e7d1eae0f508238 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/ParenBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,10 @@ final class ParensSpecial extends RNode {
 @RBuiltin(name = "(", kind = PRIMITIVE, parameterNames = {""}, visibility = ON, behavior = PURE)
 public final class ParenBuiltin extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(ParenBuiltin.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] args, @SuppressWarnings("unused") boolean inReplacement) {
         if (signature == ArgumentsSignature.empty(1)) {
             return new ParensSpecial(args[0]);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/RepeatBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/RepeatBuiltin.java
index 457a84b43eaad8023f769941eeeb642fec26fe59..5b612ffdcf8b3c09076f245bda69d7fb4d393ef7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/RepeatBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/RepeatBuiltin.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "repeat", visibility = OFF, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
 public abstract class RepeatBuiltin extends RBuiltinNode {
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doIt(Object x) {
+    protected Object doIt(@SuppressWarnings("unused") Object x) {
         throw RInternalError.unimplemented();
     }
 }
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 971e6e19765f800c98f1d7d9f958ceacecb3440b..501753254b73bcfac9933452900ba9ae7c2b3929 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.builtin.base.infix;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
@@ -172,7 +171,7 @@ class SpecialsUtils {
     }
 
     @NodeInfo(cost = NodeCost.NONE)
-    @NodeChildren({@NodeChild(value = "delegate", type = RNode.class)})
+    @NodeChild(value = "delegate", type = RNode.class)
     @TypeSystemReference(EmptyTypeSystemFlatLayout.class)
     public abstract static class ConvertIndex extends RNode {
 
@@ -200,7 +199,7 @@ class SpecialsUtils {
             }
         }
 
-        @Specialization(contains = {"convertInteger", "convertDouble"})
+        @Specialization(replaces = {"convertInteger", "convertDouble"})
         protected Object convert(Object value) {
             return value;
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java
index 639d98960d7c6d646e830621a8926430c80d9136..144f70966bb6ff034fb6de41078cce871018e1e5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subscript.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 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.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
@@ -66,7 +65,8 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 /**
  * Subscript code for vectors minus list is the same as subset code, this class allows sharing it.
  */
-@NodeChildren({@NodeChild(value = "vector", type = ProfiledValue.class), @NodeChild(value = "index", type = ConvertIndex.class)})
+@NodeChild(value = "vector", type = ProfiledValue.class)
+@NodeChild(value = "index", type = ConvertIndex.class)
 abstract class SubscriptSpecialBase extends SubscriptSpecialCommon {
 
     protected SubscriptSpecialBase(boolean inReplacement) {
@@ -104,7 +104,9 @@ abstract class SubscriptSpecialBase extends SubscriptSpecialCommon {
 /**
  * Subscript code for matrices minus list is the same as subset code, this class allows sharing it.
  */
-@NodeChildren({@NodeChild(value = "vector", type = ProfiledValue.class), @NodeChild(value = "index1", type = ConvertIndex.class), @NodeChild(value = "index2", type = ConvertIndex.class)})
+@NodeChild(value = "vector", type = ProfiledValue.class)
+@NodeChild(value = "index1", type = ConvertIndex.class)
+@NodeChild(value = "index2", type = ConvertIndex.class)
 abstract class SubscriptSpecial2Base extends SubscriptSpecial2Common {
 
     protected SubscriptSpecial2Base(boolean inReplacement) {
@@ -190,6 +192,10 @@ public abstract class Subscript extends RBuiltinNode {
         // same implementation as "[[", with different dispatch
     }
 
+    static {
+        Casts.noCasts(Subscript.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] arguments, boolean inReplacement) {
         if (signature.getNonNullCount() == 0) {
             if (arguments.length == 2) {
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 b36cbf5a3e24f4d056b0d5a8de2a166d631cd83d..82199ccb54e0f2d861beb07bba78376d41e3f74d 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,6 @@ 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.nodes.builtin.base.infix.SpecialsUtils.ConvertIndex;
 import com.oracle.truffle.r.nodes.builtin.base.infix.SpecialsUtils.ProfiledValue;
@@ -136,8 +135,8 @@ public abstract class Subset extends RBuiltinNode {
 
     @Child private ExtractVectorNode extractNode = ExtractVectorNode.create(ElementAccessMode.SUBSET, false);
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(Subset.class);
         casts.arg("drop").asLogicalVector();
     }
 
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 aa565195905cc4af852dcf237e0dfbf9e6d2adaf..5376735712f03ae5cba2f47de923ae1cd46b0f78 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,10 @@ public abstract class Tilde extends RBuiltinNode {
 
     @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
 
+    static {
+        Casts.noCasts(Tilde.class);
+    }
+
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RMissing.instance, RMissing.instance};
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 edb89de721d58a14448121bc9a634559c5c12258..d5ff59a1c998bf95082b0f30f173738d2e50f227 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode;
 import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode;
-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.nodes.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.nodes.unary.CastListNode;
@@ -85,7 +85,7 @@ abstract class UpdateFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
         return list;
     }
 
-    @Specialization(contains = "doList", guards = {"isSimpleList(list)", "!list.isShared()", "list.getNames() != null", "isNotRNullRList(value)"})
+    @Specialization(replaces = "doList", guards = {"isSimpleList(list)", "!list.isShared()", "list.getNames() != null", "isNotRNullRList(value)"})
     public RList doListDynamic(RList list, String field, Object value) {
         int index = getIndex(getNamesNode.getNames(list), field);
         if (index == -1) {
@@ -119,14 +119,14 @@ abstract class UpdateFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
 @TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 public abstract class UpdateField extends RBuiltinNode {
 
-    @Child private ReplaceVectorNode update = ReplaceVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
+    @Child private ReplaceVectorNode update = ReplaceVectorNode.create(ElementAccessMode.FIELD_SUBSCRIPT, true);
     @Child private CastListNode castList;
 
     private final ConditionProfile coerceList = ConditionProfile.createBinaryProfile();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(1).defaultError(Message.INVALID_SUBSCRIPT).mustBe(stringValue()).asStringVector().findFirst();
+    static {
+        Casts casts = new Casts(UpdateField.class);
+        casts.arg(1).defaultError(Message.INVALID_SUBSCRIPT).mustBe(stringValue(), RError.NO_CALLER, Message.INVALID_SUBSCRIPT_TYPE, Predef.typeName()).asStringVector().findFirst();
     }
 
     public static RNode createSpecial(ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
index 1488822ff52f5d2ecad17d08cfad470af6f3ad33..cfc2f94db133139d1c2ff70524b496ab21a1b2ae 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Fallback;
 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.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
@@ -60,7 +59,9 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
-@NodeChildren({@NodeChild(value = "vector", type = ProfiledValue.class), @NodeChild(value = "index", type = ConvertIndex.class), @NodeChild(value = "value", type = RNode.class)})
+@NodeChild(value = "vector", type = ProfiledValue.class)
+@NodeChild(value = "index", type = ConvertIndex.class)
+@NodeChild(value = "value", type = RNode.class)
 abstract class UpdateSubscriptSpecial extends SubscriptSpecialCommon {
 
     protected UpdateSubscriptSpecial(boolean inReplacement) {
@@ -108,8 +109,10 @@ abstract class UpdateSubscriptSpecial extends SubscriptSpecialCommon {
     }
 }
 
-@NodeChildren({@NodeChild(value = "vector", type = ProfiledValue.class), @NodeChild(value = "index1", type = ConvertIndex.class), @NodeChild(value = "index2", type = ConvertIndex.class),
-                @NodeChild(value = "value", type = RNode.class)})
+@NodeChild(value = "vector", type = ProfiledValue.class)
+@NodeChild(value = "index1", type = ConvertIndex.class)
+@NodeChild(value = "index2", type = ConvertIndex.class)
+@NodeChild(value = "value", type = RNode.class)
 abstract class UpdateSubscriptSpecial2 extends SubscriptSpecial2Common {
 
     protected UpdateSubscriptSpecial2(boolean inReplacement) {
@@ -165,6 +168,10 @@ public abstract class UpdateSubscript extends RBuiltinNode {
 
     private final ConditionProfile argsLengthLargerThanOneProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(UpdateSubscript.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] args, boolean inReplacement) {
         if (SpecialsUtils.isCorrectUpdateSignature(signature) && (args.length == 3 || args.length == 4)) {
             ProfiledValue vector = profile(args[0]);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java
index 4e9fd8094a382c3eb0695c56baa8cce51cd91a4a..30ad8a85fcf3cd07e9c6cafed84b6744df555820 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubset.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,6 +54,10 @@ public abstract class UpdateSubset extends RBuiltinNode {
     @Child private ReplaceVectorNode replaceNode = ReplaceVectorNode.create(ElementAccessMode.SUBSET, false);
     private final ConditionProfile argsLengthLargerThanOneProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(UpdateSubset.class);
+    }
+
     public static RNode special(ArgumentsSignature signature, RNode[] args, boolean inReplacement) {
         if (SpecialsUtils.isCorrectUpdateSignature(signature) && (args.length == 3 || args.length == 4)) {
             ProfiledValue vector = profile(args[0]);
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 16b9bb88af79e024667165cbd2360c2d42233b72..458380020c8600ab1b9889bcb97cbf7592f85f23 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
@@ -104,7 +104,8 @@ public final class ValuePrinterNode extends RBaseNode {
         @Child private SetFixedAttributeNode namesAttrSetter = SetFixedAttributeNode.createNames();
         @Child private SetFixedAttributeNode isTruffleObjAttrSetter = SetFixedAttributeNode.create("is.truffle.object");
 
-        public Object convert(VirtualFrame frame, TruffleObject obj) {
+        @TruffleBoundary
+        public Object convert(TruffleObject obj) {
             class RStringWrapper extends TruffleObjectWrapper implements RAbstractStringVector {
                 final TruffleObject object;
 
@@ -122,9 +123,9 @@ public final class ValuePrinterNode extends RBaseNode {
                 public String getDataAt(int index) {
                     Object value;
                     try {
-                        value = ForeignAccess.sendRead(readNode, frame, object, index);
-                        if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, frame, (TruffleObject) value)) {
-                            value = ForeignAccess.sendUnbox(unboxNode, frame, (TruffleObject) value);
+                        value = ForeignAccess.sendRead(readNode, object, index);
+                        if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) {
+                            value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value);
                         }
                     } catch (UnknownIdentifierException | UnsupportedMessageException e) {
                         throw RInternalError.shouldNotReachHere(e);
@@ -143,17 +144,16 @@ public final class ValuePrinterNode extends RBaseNode {
                 }
             }
             try {
-                if (ForeignAccess.sendHasSize(hasSizeNode, frame, obj)) {
-                    CompilerDirectives.transferToInterpreter();
-                    int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, frame, obj);
+                if (ForeignAccess.sendHasSize(hasSizeNode, obj)) {
+                    int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, obj);
                     boolean allBoolean = true;
                     boolean allInteger = true;
                     boolean allNumber = true;
                     boolean allString = true;
                     for (int i = 0; i < size; i++) {
-                        Object value = ForeignAccess.sendRead(readNode, frame, obj, i);
-                        if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, frame, (TruffleObject) value)) {
-                            value = ForeignAccess.sendUnbox(unboxNode, frame, (TruffleObject) value);
+                        Object value = ForeignAccess.sendRead(readNode, obj, i);
+                        if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) {
+                            value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value);
                         }
                         allBoolean &= value instanceof Boolean;
                         allInteger &= value instanceof Integer;
@@ -176,9 +176,9 @@ public final class ValuePrinterNode extends RBaseNode {
                             public byte getDataAt(int index) {
                                 Object value;
                                 try {
-                                    value = ForeignAccess.sendRead(readNode, frame, obj, index);
-                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, frame, (TruffleObject) value)) {
-                                        value = ForeignAccess.sendUnbox(unboxNode, frame, (TruffleObject) value);
+                                    value = ForeignAccess.sendRead(readNode, obj, index);
+                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) {
+                                        value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value);
                                     }
                                 } catch (UnknownIdentifierException | UnsupportedMessageException e) {
                                     throw RInternalError.shouldNotReachHere(e);
@@ -213,9 +213,9 @@ public final class ValuePrinterNode extends RBaseNode {
                             public int getDataAt(int index) {
                                 Object value;
                                 try {
-                                    value = ForeignAccess.sendRead(readNode, frame, obj, index);
-                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, frame, (TruffleObject) value)) {
-                                        value = ForeignAccess.sendUnbox(unboxNode, frame, (TruffleObject) value);
+                                    value = ForeignAccess.sendRead(readNode, obj, index);
+                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) {
+                                        value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value);
                                     }
                                 } catch (UnknownIdentifierException | UnsupportedMessageException e) {
                                     throw RInternalError.shouldNotReachHere(e);
@@ -250,9 +250,9 @@ public final class ValuePrinterNode extends RBaseNode {
                             public double getDataAt(int index) {
                                 Object value;
                                 try {
-                                    value = ForeignAccess.sendRead(readNode, frame, obj, index);
-                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, frame, (TruffleObject) value)) {
-                                        value = ForeignAccess.sendUnbox(unboxNode, frame, (TruffleObject) value);
+                                    value = ForeignAccess.sendRead(readNode, obj, index);
+                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) {
+                                        value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value);
                                     }
                                 } catch (UnknownIdentifierException | UnsupportedMessageException e) {
                                     throw RInternalError.shouldNotReachHere(e);
@@ -289,9 +289,9 @@ public final class ValuePrinterNode extends RBaseNode {
                             public Object getDataAt(int index) {
                                 Object value;
                                 try {
-                                    value = ForeignAccess.sendRead(readNode, frame, obj, index);
-                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, frame, (TruffleObject) value)) {
-                                        value = ForeignAccess.sendUnbox(unboxNode, frame, (TruffleObject) value);
+                                    value = ForeignAccess.sendRead(readNode, obj, index);
+                                    if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) {
+                                        value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value);
                                     }
                                 } catch (UnknownIdentifierException | UnsupportedMessageException e) {
                                     throw RInternalError.shouldNotReachHere(e);
@@ -312,9 +312,9 @@ public final class ValuePrinterNode extends RBaseNode {
                         return new RListWrapper(size);
                     }
                 }
-                TruffleObject keys = (TruffleObject) ForeignAccess.send(keysNode, frame, obj);
+                TruffleObject keys = (TruffleObject) ForeignAccess.send(keysNode, obj);
                 if (keys != null) {
-                    int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, frame, keys);
+                    int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, keys);
                     RAbstractStringVector abstractNames = new RStringWrapper(size, keys);
                     RStringVector names = RDataFactory.createStringVector(size);
                     for (int i = 0; i < size; i++) {
@@ -339,9 +339,9 @@ public final class ValuePrinterNode extends RBaseNode {
                         public Object getDataAt(int index) {
                             Object value;
                             try {
-                                value = ForeignAccess.sendRead(readNode, frame, obj, names.getDataAt(index));
-                                if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, frame, (TruffleObject) value)) {
-                                    value = ForeignAccess.sendUnbox(unboxNode, frame, (TruffleObject) value);
+                                value = ForeignAccess.sendRead(readNode, obj, names.getDataAt(index));
+                                if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) {
+                                    value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value);
                                 }
                             } catch (UnknownIdentifierException | UnsupportedMessageException e) {
                                 throw RInternalError.shouldNotReachHere(e);
@@ -405,20 +405,20 @@ public final class ValuePrinterNode extends RBaseNode {
         return boxPrimitiveNode.execute(o);
     }
 
-    private Object convertTruffleObject(VirtualFrame frame, Object o) {
+    private Object convertTruffleObject(Object o) {
         if (o instanceof TruffleObject && !(o instanceof RTypedValue)) {
             if (convertTruffleObject == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 convertTruffleObject = insert(new ConvertTruffleObjectNode());
             }
-            return convertTruffleObject.convert(frame, (TruffleObject) o);
+            return convertTruffleObject.convert((TruffleObject) o);
         }
         return o;
     }
 
-    public String execute(VirtualFrame frame, Object o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt) {
+    public String execute(Object o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt) {
         try {
-            prettyPrint(convertTruffleObject(frame, o), new PrintParameters(digits, quote, naPrint, printGap, right, max, useSource, noOpt), RWriter::new);
+            prettyPrint(convertTruffleObject(o), new PrintParameters(digits, quote, naPrint, printGap, right, max, useSource, noOpt), RWriter::new);
             return null;
         } catch (IOException ex) {
             throw RError.ioError(this, ex);
@@ -576,12 +576,8 @@ public final class ValuePrinterNode extends RBaseNode {
         }
     }
 
-    public Object prettyPrint(VirtualFrame frame, Object v, WriterFactory wf) {
-        return prettyPrint(convertTruffleObject(frame, v), wf);
-    }
-
     @TruffleBoundary
-    private Object prettyPrint(Object v, WriterFactory wf) {
+    public Object prettyPrint(Object v, WriterFactory wf) {
         PrintParameters printParams = new PrintParameters();
         printParams.setDefaults();
         printParams.setSuppressIndexLabels(true);
@@ -619,7 +615,7 @@ public final class ValuePrinterNode extends RBaseNode {
 
             @Override
             public Object execute(VirtualFrame frame) {
-                return valuePrinterNode.prettyPrint(frame, value, AnyVectorToStringVectorWriter::new);
+                return valuePrinterNode.prettyPrint(value, AnyVectorToStringVectorWriter::new);
             }
         }).call(value);
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java
index a045122de665406cca5d5bfd8055822a482bd2d2..ad08dd85ae9969918a2a38814598b27c7698c74c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/SystemFunction.java
@@ -30,7 +30,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -40,8 +39,8 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 public abstract class SystemFunction extends RBuiltinNode {
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(SystemFunction.class);
         casts.arg("command").mustBe(stringValue(), RError.Message.SYSTEM_CHAR_ARG).asStringVector().findFirst();
         casts.arg("intern").asLogicalVector().findFirst().notNA(RError.Message.SYSTEM_INTERN_NOT_NA).map(toBoolean());
     }
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 afe6563893bb3378fd0cad02e00a5fc4316aa962..2b3370bbb83ffad321c38ec351176d4413261ab8 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
@@ -37,15 +37,13 @@ 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.api.vm.PolyglotEngine;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RChannel;
-import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
-import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.ContextInfo;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -62,27 +60,25 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
  */
 public class FastRContext {
 
-    private static final String[] EMPTY = new String[0];
-
-    private static final class Casts {
-        private static void exprs(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void exprs(Casts casts) {
             casts.arg("exprs").asStringVector().mustBe(notEmpty());
         }
 
-        private static void kind(CastBuilder casts) {
+        private static void kind(Casts casts) {
             casts.arg("kind").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().notNA().mustBe(
                             equalTo(RContext.ContextKind.SHARE_NOTHING.name()).or(equalTo(RContext.ContextKind.SHARE_PARENT_RW.name()).or(equalTo(RContext.ContextKind.SHARE_PARENT_RO.name()))));
         }
 
-        private static void pc(CastBuilder casts) {
+        private static void pc(Casts casts) {
             casts.arg("pc").asIntegerVector().findFirst().notNA().mustBe(gt(0));
         }
 
-        private static void key(CastBuilder casts) {
+        private static void key(Casts casts) {
             casts.arg("key").asIntegerVector().mustBe(notEmpty()).findFirst();
         }
 
-        private static void id(CastBuilder casts) {
+        private static void id(Casts casts) {
             casts.arg("id").asIntegerVector().mustBe(notEmpty()).findFirst();
         }
     }
@@ -109,11 +105,11 @@ public class FastRContext {
             return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.exprs(casts);
-            Casts.pc(casts);
-            Casts.kind(casts);
+        static {
+            Casts casts = new Casts(Spawn.class);
+            CastsHelper.exprs(casts);
+            CastsHelper.pc(casts);
+            CastsHelper.kind(casts);
         }
 
         @Specialization
@@ -136,8 +132,9 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.context.join", visibility = OFF, kind = PRIMITIVE, parameterNames = {"handle"}, behavior = COMPLEX)
     public abstract static class Join extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(Join.class);
             casts.arg("handle").asIntegerVector().mustBe(notEmpty());
         }
 
@@ -180,11 +177,11 @@ public class FastRContext {
             return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.exprs(casts);
-            Casts.pc(casts);
-            Casts.kind(casts);
+        static {
+            Casts casts = new Casts(Eval.class);
+            CastsHelper.exprs(casts);
+            CastsHelper.pc(casts);
+            CastsHelper.kind(casts);
         }
 
         @Specialization
@@ -231,8 +228,8 @@ public class FastRContext {
             return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(R.class);
             casts.arg("args").allowMissing().mustBe(stringValue());
             casts.arg("env").allowMissing().mustBe(stringValue());
             casts.arg("intern").asLogicalVector().findFirst().map(toBoolean());
@@ -267,8 +264,8 @@ public class FastRContext {
             return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Rscript.class);
             casts.arg("args").mustBe(stringValue(), RError.Message.GENERIC, "usage: /path/to/Rscript [--options] [-e expr [-e expr2 ...] | file] [args]").asStringVector();
             casts.arg("env").allowMissing().mustBe(stringValue());
             casts.arg("intern").asLogicalVector().findFirst().map(toBoolean());
@@ -295,17 +292,15 @@ public class FastRContext {
     }
 
     private static ContextInfo createContextInfo(RContext.ContextKind contextKind) {
-        RStartParams startParams = new RStartParams(RCmdOptions.parseArguments(Client.RSCRIPT, EMPTY, false), false);
-        ContextInfo info = ContextInfo.create(startParams, null, contextKind, RContext.getInstance(), RContext.getInstance().getConsoleHandler());
-        return info;
+        return ContextInfo.createNoRestore(Client.RSCRIPT, null, contextKind, RContext.getInstance(), RContext.getInstance().getConsoleHandler());
     }
 
     @RBuiltin(name = ".fastr.channel.create", kind = PRIMITIVE, parameterNames = {"key"}, behavior = COMPLEX)
     public abstract static class CreateChannel extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.key(casts);
+        static {
+            Casts casts = new Casts(CreateChannel.class);
+            CastsHelper.key(casts);
         }
 
         @Specialization
@@ -317,9 +312,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.get", kind = PRIMITIVE, parameterNames = {"key"}, behavior = COMPLEX)
     public abstract static class GetChannel extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.key(casts);
+
+        static {
+            Casts casts = new Casts(GetChannel.class);
+            CastsHelper.key(casts);
         }
 
         @Specialization
@@ -331,9 +327,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.close", visibility = OFF, kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
     public abstract static class CloseChannel extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(CloseChannel.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -346,9 +343,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.send", visibility = OFF, kind = PRIMITIVE, parameterNames = {"id", "data"}, behavior = COMPLEX)
     public abstract static class ChannelSend extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(ChannelSend.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -361,9 +359,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.receive", kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
     public abstract static class ChannelReceive extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(ChannelReceive.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -375,9 +374,10 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.poll", kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
     public abstract static class ChannelPoll extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.id(casts);
+
+        static {
+            Casts casts = new Casts(ChannelPoll.class);
+            CastsHelper.id(casts);
         }
 
         @Specialization
@@ -389,8 +389,9 @@ public class FastRContext {
 
     @RBuiltin(name = ".fastr.channel.select", kind = PRIMITIVE, parameterNames = {"ids"}, behavior = COMPLEX)
     public abstract static class ChannelSelect extends RBuiltinNode {
-        @Override
-        protected void createCasts(CastBuilder casts) {
+
+        static {
+            Casts casts = new Casts(ChannelSelect.class);
             casts.arg("ids").mustBe(instanceOf(RList.class));
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java
index e867b73ba1900ccd5040a1f346128a42fa1e48b5..6dd3870946dc0b52c010c7690ddbb329cab61706 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRDebug.java
@@ -28,7 +28,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -38,8 +37,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 @RBuiltin(name = ".fastr.debug", visibility = OFF, kind = PRIMITIVE, parameterNames = {"values"}, behavior = COMPLEX)
 public abstract class FastRDebug extends RBuiltinNode {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRDebug.class);
         casts.arg("values").asStringVector();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
index cb129360b7b21c4c5a513fab08d6850f4524f15a..5b76a6ac968905d6039b7e8c80a0707e08b4a6ca 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,10 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 @RBuiltin(name = ".fastr.identity", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
 public abstract class FastRIdentity extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(FastRIdentity.class);
+    }
+
     @Specialization
     @TruffleBoundary
     protected int typeof(Object x) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInspect.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInspect.java
index b3ee8227c3d2db6bb72e83df13246bc4a9b42f40..39cb3d17be08313cfcb2b864857c22afde8472db 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInspect.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInspect.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,11 @@ import com.oracle.truffle.r.runtime.data.RNull;
  */
 @RBuiltin(name = ".fastr.inspect", visibility = OFF, kind = PRIMITIVE, parameterNames = {"..."}, behavior = COMPLEX)
 public abstract class FastRInspect extends RBuiltinNode {
+
+    static {
+        Casts.noCasts(FastRInspect.class);
+    }
+
     @Specialization
     public Object call(@SuppressWarnings("unused") RArgsValuesAndNames args) {
         return RNull.instance;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
index f0a1eaaf6eadefcfdc832fa191210af6fe13681e..16cc34b1b57661dc0db381a6f0d57db48be81cd0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,14 +41,12 @@ import com.oracle.truffle.api.Truffle;
 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.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.DirectCallNode;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.Source.Builder;
-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;
@@ -66,8 +64,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.eval", visibility = OFF, kind = PRIMITIVE, parameterNames = {"mimeType", "source"}, behavior = COMPLEX)
     public abstract static class Eval extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Eval.class);
             casts.arg("mimeType").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
             casts.arg("source").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
@@ -89,14 +87,14 @@ public class FastRInterop {
 
         @SuppressWarnings("unused")
         @Specialization(guards = {"cachedMimeType != null", "cachedMimeType.equals(mimeType)", "cachedSource != null", "cachedSource.equals(source)"})
-        protected Object evalCached(VirtualFrame frame, String mimeType, String source,
+        protected Object evalCached(String mimeType, String source,
                         @Cached("mimeType") String cachedMimeType,
                         @Cached("source") String cachedSource,
                         @Cached("createCall(mimeType, source)") DirectCallNode call) {
-            return call.call(frame, EMPTY_OBJECT_ARRAY);
+            return call.call(EMPTY_OBJECT_ARRAY);
         }
 
-        @Specialization(contains = "evalCached")
+        @Specialization(replaces = "evalCached")
         @TruffleBoundary
         protected Object eval(String mimeType, String source) {
             return parse(mimeType, source).call();
@@ -106,8 +104,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.evalFile", visibility = OFF, kind = PRIMITIVE, parameterNames = {"path", "mimeType"}, behavior = COMPLEX)
     public abstract static class EvalFile extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(EvalFile.class);
             casts.arg("path").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
             casts.arg("mimeType").allowMissing().mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
@@ -146,8 +144,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.export", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name", "value"}, behavior = COMPLEX)
     public abstract static class Export extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Export.class);
             casts.arg("name").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
             casts.arg("value").boxPrimitive();
         }
@@ -178,8 +176,8 @@ public class FastRInterop {
     @RBuiltin(name = ".fastr.interop.import", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX)
     public abstract static class Import extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(Import.class);
             casts.arg("name").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
         }
 
@@ -199,9 +197,13 @@ public class FastRInterop {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.HAS_SIZE.createNode();
 
+        static {
+            Casts.noCasts(HasSize.class);
+        }
+
         @Specialization
-        public byte hasSize(VirtualFrame frame, TruffleObject obj) {
-            return RRuntime.asLogical(ForeignAccess.sendHasSize(node, frame, obj));
+        public byte hasSize(TruffleObject obj) {
+            return RRuntime.asLogical(ForeignAccess.sendHasSize(node, obj));
         }
     }
 
@@ -210,9 +212,13 @@ public class FastRInterop {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.IS_NULL.createNode();
 
+        static {
+            Casts.noCasts(IsNull.class);
+        }
+
         @Specialization
-        public byte hasSize(VirtualFrame frame, TruffleObject obj) {
-            return RRuntime.asLogical(ForeignAccess.sendIsNull(node, frame, obj));
+        public byte hasSize(TruffleObject obj) {
+            return RRuntime.asLogical(ForeignAccess.sendIsNull(node, obj));
         }
     }
 
@@ -221,17 +227,21 @@ public class FastRInterop {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.IS_EXECUTABLE.createNode();
 
+        static {
+            Casts.noCasts(IsExecutable.class);
+        }
+
         @Specialization
-        public byte hasSize(VirtualFrame frame, TruffleObject obj) {
-            return RRuntime.asLogical(ForeignAccess.sendIsExecutable(node, frame, obj));
+        public byte hasSize(TruffleObject obj) {
+            return RRuntime.asLogical(ForeignAccess.sendIsExecutable(node, obj));
         }
     }
 
     @RBuiltin(name = ".fastr.interop.toBoolean", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
     public abstract static class ToBoolean extends RBuiltinNode {
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
+        static {
+            Casts casts = new Casts(ToBoolean.class);
             casts.arg("value").mustBe(logicalValue()).asLogicalVector().mustBe(singleElement()).findFirst().mustBe(notLogicalNA()).map(Predef.toBoolean());
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java
index d072a3ad7688d02a242fa9763e46443b29037c8c..0306c6dc7a9167fbf5df2da024ede7f38acbe35f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRPkgSource.java
@@ -37,7 +37,6 @@ import java.nio.file.Path;
 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.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
@@ -70,8 +69,8 @@ public abstract class FastRPkgSource extends RBuiltinNode {
         return new Object[]{RNull.instance, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    public void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRPkgSource.class);
         casts.arg("pkgs").mustBe(stringValue());
         casts.arg("verbose").asLogicalVector().findFirst().notNA().map(toBoolean());
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
index 600608775cb0b6820c71684c03804b9c3453b466..a9e8cee05edafc523f5399c3ee63f76324ee33d0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,10 @@ import com.oracle.truffle.r.runtime.data.RShareable;
 @RBuiltin(name = ".fastr.refcountinfo", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
 public abstract class FastRRefCountInfo extends RBuiltinNode {
 
+    static {
+        Casts.noCasts(FastRRefCountInfo.class);
+    }
+
     @Specialization
     protected int refcount(Object x) {
         if (x instanceof RShareable) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java
index fbc559dc1a4a373de901ed544c2f28d9bc068a0b..f2b4d2b4d54af8bc4024cea49df6cf1b5b5b8679 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStackTrace.java
@@ -29,7 +29,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
@@ -45,8 +44,8 @@ public abstract class FastRStackTrace extends RBuiltinNode {
         return new Object[]{RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRStackTrace.class);
         casts.arg("print.frame.contents").asLogicalVector().findFirst().map(toBoolean());
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java
index dc521a05ffc1375c069d2b463954d8228e13d1cc..16abbd8f1637e254b177583593c0f21dabdc7cb0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRStats.java
@@ -42,7 +42,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -62,12 +62,12 @@ import com.oracle.truffle.tools.Profiler.Counter.TimeKind;
 
 public class FastRStats {
 
-    private static final class Casts {
-        private static void filename(CastBuilder casts) {
+    private static final class CastsHelper {
+        private static void filename(Casts casts) {
             casts.arg("filename").allowNull().mustBe(stringValue()).asStringVector();
         }
 
-        private static void append(CastBuilder casts) {
+        private static void append(Casts casts) {
             casts.arg("append").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).notNA().map(toBoolean());
         }
     }
@@ -79,10 +79,10 @@ public class FastRStats {
             return new Object[]{"Rprofattr.out", RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.filename(casts);
-            Casts.append(casts);
+        static {
+            Casts casts = new Casts(FastRProfAttr.class);
+            CastsHelper.filename(casts);
+            CastsHelper.append(casts);
         }
 
         @SuppressWarnings("unused")
@@ -164,10 +164,10 @@ public class FastRStats {
             return new Object[]{"Rproftypecounts.out", RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.filename(casts);
-            Casts.append(casts);
+        static {
+            Casts casts = new Casts(FastRProfTypecounts.class);
+            CastsHelper.filename(casts);
+            CastsHelper.append(casts);
         }
 
         @SuppressWarnings("unused")
@@ -295,10 +295,10 @@ public class FastRStats {
             return new Object[]{"Rproffuncounts.out", RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE, 0, RRuntime.LOGICAL_FALSE};
         }
 
-        @Override
-        protected void createCasts(CastBuilder casts) {
-            Casts.filename(casts);
-            Casts.append(casts);
+        static {
+            Casts casts = new Casts(FastRProfFuncounts.class);
+            CastsHelper.filename(casts);
+            CastsHelper.append(casts);
             casts.arg("timing").asLogicalVector().findFirst().notNA().map(toBoolean());
             casts.arg("threshold").asIntegerVector().findFirst().notNA();
             casts.arg("histograms").asLogicalVector().findFirst().notNA().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java
index 580be8e81f89dc0d86ce4039640f9a6cd79abca6..8817ee3bcf7189734a8924abbc357265c6df5791 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSyntaxTree.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeVisitor;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags;
@@ -74,8 +73,8 @@ public abstract class FastRSyntaxTree extends RBuiltinNode {
         return new Object[]{RMissing.instance, "syntaxelement", RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRSyntaxTree.class);
         casts.arg("func").mustBe(instanceOf(RFunction.class));
         casts.arg("visitMode").asStringVector().findFirst();
         casts.arg("printSource").asLogicalVector().findFirst().map(toBoolean());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
index c24b8abdd4cc8a7d1f4a1b953ffb178fd0a94769..aa63c269457a97afd0f10107682f85fc22e5b6d5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRThrowIt.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ 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.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RError;
@@ -38,8 +37,9 @@ import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = ".fastr.throw", kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX)
 public abstract class FastRThrowIt extends RBuiltinNode {
-    @Override
-    protected void createCasts(CastBuilder casts) {
+
+    static {
+        Casts casts = new Casts(FastRThrowIt.class);
         casts.arg("name").asStringVector().findFirst();
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java
index e2ead78ab4f671cb31cc1e16b71d9b7e9306a683..96eec41e231eac409ac72b9ed067e3c04168ada0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTrace.java
@@ -115,6 +115,10 @@ public class FastRTrace {
         @Child private CastLogicalNode castLogical;
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
+        static {
+            Casts.noCasts(Trace.class);
+        }
+
         @Specialization
         protected Object trace(VirtualFrame frame, Object whatObj, Object tracer, Object exit, Object at, Object printObj, Object signature, Object whereObj) {
             Object what = whatObj;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java
index 01682e5fbdd37758b76dae86366ea339ad2bc5b8..7071bb26a0b839e61a49f0997f1738cff88abfd1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTree.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.NodeUtil;
 import com.oracle.truffle.api.nodes.RootNode;
-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;
@@ -46,8 +45,8 @@ public abstract class FastRTree extends RBuiltinNode {
         return new Object[]{RMissing.instance, RRuntime.LOGICAL_FALSE};
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastRTree.class);
         casts.arg("func").mustBe(instanceOf(RFunction.class));
         casts.arg("verbose").asLogicalVector().findFirst().map(toBoolean());
 
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 4f36ba52d0e3d898517ba8461e3c8cb7a048cd30..45a57b19326df2fafe3f82f8218977900929712a 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
@@ -27,12 +27,9 @@ 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.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.access.FrameSlotNode;
 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.nodes.function.call.RExplicitCallNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -45,20 +42,18 @@ import com.oracle.truffle.r.runtime.data.RFunction;
  */
 @RBuiltin(name = ".fastr.try", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
 public abstract class FastRTry extends RBuiltinNode {
-    private final Object argsIdentifier = new Object();
-    @Child private RCallBaseNode call = RCallNode.createExplicitCall(argsIdentifier);
-    @Child private FrameSlotNode slot = FrameSlotNode.createTemp(argsIdentifier, true);
+    @Child private RExplicitCallNode call = RExplicitCallNode.create();
+
+    static {
+        Casts.noCasts(FastRTry.class);
+    }
 
     @Specialization
     public Object tryFunc(VirtualFrame frame, RFunction func) {
-        FrameSlot frameSlot = slot.executeFrameSlot(frame);
         try {
-            frame.setObject(frameSlot, RArgsValuesAndNames.EMPTY);
-            call.execute(frame, func);
+            call.execute(frame, func, RArgsValuesAndNames.EMPTY);
         } catch (Throwable ex) {
             return formatError(ex);
-        } finally {
-            frame.setObject(frameSlot, null);
         }
         return RRuntime.LOGICAL_TRUE;
     }
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 714e8c2a381a8dd49dd583944e2439d4e5d3ef7d..fb4cc5a0b3a335acb99cdb2b2f0eb05b781063c2 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
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2016, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -19,7 +19,6 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.dsl.Cached;
 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.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -43,8 +42,8 @@ public abstract class FastrDqrls extends RBuiltinNode {
     private static final String[] NAMES = new String[]{"qr", "coefficients", "residuals", "effects", "rank", "pivot", "qraux", "tol", "pivoted"};
     private static RStringVector namesVector = null;
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(FastrDqrls.class);
         casts.arg("x").asDoubleVector(true, true, true);
         casts.arg("n").asIntegerVector().findFirst();
         casts.arg("p").asIntegerVector().findFirst();
@@ -60,7 +59,7 @@ public abstract class FastrDqrls extends RBuiltinNode {
         return call(xVec, xVec.materialize(), n, p, yVec, yVec.materialize(), ny, tol, coeffVec);
     }
 
-    @Specialization(contains = "doDouble")
+    @Specialization(replaces = "doDouble")
     public RList doOther(RAbstractVector xVec, int n, int p, RAbstractVector yVec, int ny, double tol, RAbstractDoubleVector coeffVec, @Cached(value = "create()") CastDoubleNode castNode) {
         return call(xVec, ((RAbstractDoubleVector) castNode.execute(xVec)).materialize(), n, p, yVec, ((RAbstractDoubleVector) castNode.execute(yVec)).materialize(), ny, tol, coeffVec);
     }
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 f092a88c2a04709480ccf6d14e00faac3fbbd08f..24e9d47732f8070bc3d3abaaa840a2faead9264a 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
@@ -22,13 +22,14 @@
  */
 package com.oracle.truffle.r.nodes.builtin;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.anyValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asBoolean;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asInteger;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asLogicalVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asStringVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.atomicIntegerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.atomicLogicalValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain;
@@ -37,6 +38,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.dimGt;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleNA;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleToInt;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.elementAt;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyStringVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.findFirst;
@@ -44,17 +46,20 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gt;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gt0;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.intNA;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.isFractional;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalTrue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.map;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.mustBe;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.not;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notNA;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullConstant;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.shouldBe;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
@@ -82,6 +87,7 @@ import com.oracle.truffle.r.nodes.casts.CastNodeSampler;
 import com.oracle.truffle.r.nodes.casts.FilterSamplerFactory;
 import com.oracle.truffle.r.nodes.casts.MapperSamplerFactory;
 import com.oracle.truffle.r.nodes.casts.Samples;
+import com.oracle.truffle.r.nodes.casts.TypeExpr;
 import com.oracle.truffle.r.nodes.test.TestUtilities;
 import com.oracle.truffle.r.nodes.test.TestUtilities.NodeHandle;
 import com.oracle.truffle.r.nodes.unary.CastNode;
@@ -99,8 +105,11 @@ 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.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 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.NewEnv;
 
 /**
  * Tests the cast pipelines and also that the samples generation process matches the intended
@@ -117,7 +126,8 @@ public class CastBuilderTest {
     private static final boolean TEST_SAMPLING = false;
 
     private CastBuilder cb;
-    private PreinitialPhaseBuilder<Object> arg;
+    private CastNode castNode;
+    private PreinitialPhaseBuilder arg;
 
     static {
         if (TEST_SAMPLING) {
@@ -131,6 +141,7 @@ public class CastBuilderTest {
     public void setUp() {
         cb = new CastBuilder(DummyBuiltin.class.getAnnotation(RBuiltin.class));
         arg = cb.arg("x");
+        castNode = null;
     }
 
     @After
@@ -396,6 +407,9 @@ public class CastBuilderTest {
     @Test
     public void testLogicalToBooleanPipeline() {
         arg.asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+        assertEquals(Boolean.TRUE, cast(RRuntime.LOGICAL_TRUE));
+        assertEquals(Boolean.FALSE, cast(RRuntime.LOGICAL_FALSE));
+        assertEquals(Boolean.FALSE, cast(RRuntime.LOGICAL_NA));
         assertEquals(Boolean.TRUE, cast(RDataFactory.createLogicalVector(new byte[]{RRuntime.LOGICAL_TRUE, RRuntime.LOGICAL_FALSE}, true)));
         assertEquals(Boolean.FALSE, cast(RDataFactory.createLogicalVector(0)));
         testPipeline(NO_FILTER_EXPECT_EMPTY_SAMPLES);
@@ -481,6 +495,21 @@ public class CastBuilderTest {
         assertCastFail(RRuntime.INT_NA);
     }
 
+    @Test
+    public void testChain2() {
+        arg.
+        mapIf(instanceOf(RAbstractListVector.class),
+           chain(asVector()).
+              with(findFirst().objectElement()).
+              end()).mustBe(instanceOf(RList.class).or(instanceOf(REnvironment.class)));
+
+        RList l = RDataFactory.createList();
+        assertEquals(l, cast(RDataFactory.createList(new Object[]{l})));
+        NewEnv env = RDataFactory.createNewEnv("aaa");
+        assertEquals(env, cast(RDataFactory.createList(new Object[]{env})));
+        assertCastPreserves(env);
+    }
+
     public Function<InitialPhaseBuilder<Object>, InitialPhaseBuilder<Object>> nonListToBoolean() {
         return phaseBuilder -> phaseBuilder.
                         mapIf(instanceOf(RList.class).not(),
@@ -521,9 +550,9 @@ public class CastBuilderTest {
     @Test
     public void testMessageArgumentAsLambda() {
         Function<Object, Object> argMsg = name -> "something";
-        arg.conf(c -> c.allowNull().mustNotBeMissing(SHOW_CALLER, RError.Message.GENERIC, argMsg)).mustBe(stringValue(), RError.Message.GENERIC, argMsg);
+        arg.mustNotBeMissing(SHOW_CALLER, RError.Message.GENERIC, argMsg).mustBe(stringValue(), RError.Message.GENERIC, argMsg);
 
-        assertCastPreserves(RNull.instance);
+        assertCastPreserves("abc");
         assertCastFail(RMissing.instance, "something");
         assertCastFail(42, "something");
     }
@@ -594,7 +623,7 @@ public class CastBuilderTest {
 
     @Test
     public void testSample22() {
-        arg.conf(c -> c.mapMissing(emptyStringVector()).mapNull(emptyStringVector())).mustBe(stringValue());
+        arg.mapIf(nullValue().or(missingValue()), emptyStringVector()).mustBe(stringValue());
         arg.mapNull(emptyStringVector()).mustBe(stringValue());
         Object res = cast(RNull.instance);
         assertTrue(res instanceof RAbstractStringVector);
@@ -606,6 +635,21 @@ public class CastBuilderTest {
         assertEquals("abc", res);
     }
 
+    @Test
+    public void testSample23() {
+        //@formatter:off
+        arg.defaultError(RError.Message.INVALID_UNNAMED_ARGUMENTS).
+            mustBe(abstractVectorValue()).
+            asIntegerVector().
+            findFirst(RRuntime.INT_NA).
+            mustBe(intNA().not().and(gte(0)));
+        //@formatter:on
+        assertEquals(1, cast(1));
+        assertEquals(1, cast(1));
+        assertEquals(1, cast("1"));
+        assertCastFail(RError.Message.INVALID_UNNAMED_ARGUMENTS.message, RRuntime.INT_NA, -1, RNull.instance);
+    }
+
     @Test
     public void testSampleNonNASequence() {
         arg.notNA(RError.Message.GENERIC, "Error");
@@ -624,7 +668,7 @@ public class CastBuilderTest {
 
     @Test
     public void testPreserveNonVectorFlag() {
-        arg.allowNull().asVector(true);
+        arg.asVector(true);
         assertEquals(RNull.instance, cast(RNull.instance));
     }
 
@@ -781,12 +825,68 @@ public class CastBuilderTest {
         Assert.assertEquals("abc", cast("abc"));
     }
 
+    @Test
+    public void testComplexFilterWithForwardedNull() {
+        arg.mustBe(nullValue().or(numericValue()).or(stringValue()).or(complexValue())).mapIf(numericValue().or(complexValue()), asIntegerVector());
+        Assert.assertEquals(RNull.instance, cast(RNull.instance));
+        Assert.assertEquals("abc", cast("abc"));
+    }
+
+    @Test
+    public void testFindFirstOrNull() {
+        arg.mustBe(nullValue().or(integerValue())).asIntegerVector().findFirstOrNull();
+        Assert.assertEquals(RNull.instance, cast(RNull.instance));
+        Assert.assertEquals(1, cast(1));
+    }
+
+    @Test
+    public void testReturnIf() {
+        arg.returnIf(nullValue(), constant(1.1)).mustBe(logicalValue()).asLogicalVector().findFirst().map(toBoolean());
+        Assert.assertEquals(1.1, cast(RNull.instance));
+        Assert.assertEquals(true, cast(RRuntime.LOGICAL_TRUE));
+    }
+
+    @Test
+    public void testNotNullAndNotMissing() {
+        arg.mustBe(nullValue().not().and(missingValue().not()));
+        try {
+            cast(RNull.instance);
+            fail();
+        } catch (Exception e) {
+        }
+        try {
+            cast(RMissing.instance);
+            fail();
+        } catch (Exception e) {
+        }
+        Assert.assertEquals("abc", cast("abc"));
+    }
+
+    @Test
+    public void testWarningInElseBranchOfMapIf() {
+        arg.mapIf(numericValue(),
+                        chain(asIntegerVector()).with(findFirst().integerElement()).end(),
+                        chain(asIntegerVector()).with(Predef.shouldBe(anyValue().not(), RError.NO_CALLER, RError.Message.NA_INTRODUCED_COERCION)).end());
+
+        Assert.assertEquals(1, cast(1));
+        Assert.assertEquals(1, cast("1"));
+        Assert.assertEquals(RError.Message.NA_INTRODUCED_COERCION.message, CastNode.getLastWarning());
+    }
+
+    @Test
+    public void testWarningInTrueBranchOfMapIf() {
+        arg.allowNull().mapIf(stringValue(), chain(asStringVector()).with(shouldBe(anyValue().not(),
+                        RError.SHOW_CALLER, RError.Message.NA_INTRODUCED_COERCION)).end(),
+                        asIntegerVector());
+        Assert.assertEquals("1", cast("1"));
+        Assert.assertEquals(RError.Message.NA_INTRODUCED_COERCION.message, CastNode.getLastWarning());
+    }
+
     /**
      * Casts given object using the configured pipeline in {@link #arg}.
      */
     private Object cast(Object a) {
-        CastNode argCastNode = cb.getCasts()[0];
-        NodeHandle<CastNode> argCastNodeHandle = TestUtilities.createHandle(argCastNode, (node, args) -> node.execute(args[0]));
+        NodeHandle<CastNode> argCastNodeHandle = TestUtilities.createHandle(getCastNode(), (node, args) -> node.execute(args[0]));
         return argCastNodeHandle.call(a);
     }
 
@@ -813,6 +913,12 @@ public class CastBuilderTest {
         assertEquals("Expected warning message", expectedMessage, CastNode.getLastWarning());
     }
 
+    private void assertCastFail(String expectedMessage, Object... values) {
+        for (Object value : values) {
+            assertCastFail(value, expectedMessage);
+        }
+    }
+
     private void assertCastFail(Object value) {
         assertCastFail(value, String.format(RError.Message.INVALID_ARGUMENT.message, "x"));
     }
@@ -834,12 +940,17 @@ public class CastBuilderTest {
         testPipeline(false);
     }
 
+    private TypeExpr resultTypes() {
+        CastNodeSampler<CastNode> sampler = CastNodeSampler.createSampler(getCastNode());
+        return sampler.resultTypes();
+    }
+
     private void testPipeline(boolean emptyPositiveSamplesAllowed) {
         if (!TEST_SAMPLING) {
             return;
         }
 
-        CastNodeSampler<CastNode> sampler = CastNodeSampler.createSampler(cb.getCasts()[0]);
+        CastNodeSampler<CastNode> sampler = CastNodeSampler.createSampler(getCastNode());
         Samples<?> samples = sampler.collectSamples();
         if (!emptyPositiveSamplesAllowed) {
             Assert.assertFalse(samples.positiveSamples().isEmpty());
@@ -847,6 +958,13 @@ public class CastBuilderTest {
         testPipeline(samples);
     }
 
+    private CastNode getCastNode() {
+        if (castNode == null) {
+            castNode = cb.getCasts()[0];
+        }
+        return castNode;
+    }
+
     private void testPipeline(Samples<?> samples) {
         if (!TEST_SAMPLING) {
             return;
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java
index 0e64e2c2cd775661cf03bad5498dce8dcaecad4a..880cfb0c9a140e3b70e4be958e3c501d3c4d50ed 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,8 @@
 package com.oracle.truffle.r.nodes.casts;
 
 import java.lang.reflect.Constructor;
+import java.util.LinkedList;
+import java.util.List;
 
 import com.oracle.truffle.r.nodes.unary.CastNode;
 
@@ -39,10 +41,15 @@ public class CastNodeSampler<T extends CastNode> {
     }
 
     public final TypeExpr resultTypes() {
-        return resultTypes(TypeExpr.ANYTHING);
+        SamplingContext ctx = new SamplingContext();
+        TypeExpr resTypes = resultTypes(TypeExpr.ANYTHING, ctx);
+        for (TypeExpr altResType : ctx.altResultTypes) {
+            resTypes = resTypes.or(altResType);
+        }
+        return resTypes;
     }
 
-    public TypeExpr resultTypes(TypeExpr inputType) {
+    public TypeExpr resultTypes(TypeExpr inputType, SamplingContext ctx) {
         return CastUtils.Casts.createCastNodeCasts(castNode.getClass().getSuperclass()).narrow(inputType);
     }
 
@@ -86,4 +93,12 @@ public class CastNodeSampler<T extends CastNode> {
             throw new IllegalArgumentException(e);
         }
     }
+
+    public static final class SamplingContext {
+        private List<TypeExpr> altResultTypes = new LinkedList<>();
+
+        public void addAltResultType(TypeExpr altResType) {
+            altResultTypes.add(altResType);
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/FilterSamplerFactory.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/FilterSamplerFactory.java
index 1886cc2aaa532fca53312c9e7487a0fcda1c4590..5341c5cef83c9aa3732224962e8203bb7fac9c2d 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/FilterSamplerFactory.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/FilterSamplerFactory.java
@@ -80,26 +80,28 @@ public final class FilterSamplerFactory
         return x -> filter.test(x);
     }
 
+    @SuppressWarnings("rawtypes")
     @Override
     public ArgumentFilterSampler<?, ?> visit(TypeFilter<?, ?> filter) {
+        Class<?>[] filterTypes = new Class[]{filter.getType1(), filter.getType2()};
         return TypePredicateArgumentFilterSampler.fromLambda(toPredicate(filter.getInstanceOfLambda()),
-                        CastUtils.sampleValuesForClases(filter.getType()), CastUtils.samples(null), filter.getType());
+                        CastUtils.sampleValuesForClases(filterTypes), CastUtils.samples(null), filterTypes);
     }
 
     @Override
     public ArgumentFilterSampler<?, ?> visit(RTypeFilter<?> filter) {
         if (filter.getType() == RType.Integer) {
-            return visit(new TypeFilter<>(x -> x instanceof Integer || x instanceof RAbstractIntVector, Integer.class, RAbstractIntVector.class));
+            return visit(new TypeFilter<>(Integer.class, RAbstractIntVector.class));
         } else if (filter.getType() == RType.Double) {
-            return visit(new TypeFilter<>(x -> x instanceof Double || x instanceof RAbstractDoubleVector, Double.class, RAbstractDoubleVector.class));
+            return visit(new TypeFilter<>(Double.class, RAbstractDoubleVector.class));
         } else if (filter.getType() == RType.Logical) {
-            return visit(new TypeFilter<>(x -> x instanceof Byte || x instanceof RAbstractLogicalVector, Byte.class, RAbstractLogicalVector.class));
+            return visit(new TypeFilter<>(Byte.class, RAbstractLogicalVector.class));
         } else if (filter.getType() == RType.Complex) {
-            return visit(new TypeFilter<>(x -> x instanceof RAbstractComplexVector, RAbstractComplexVector.class));
+            return visit(new TypeFilter<>(RAbstractComplexVector.class));
         } else if (filter.getType() == RType.Character) {
-            return visit(new TypeFilter<>(x -> x instanceof String || x instanceof RAbstractStringVector, String.class, RAbstractStringVector.class));
+            return visit(new TypeFilter<>(String.class, RAbstractStringVector.class));
         } else if (filter.getType() == RType.Raw) {
-            return visit(new TypeFilter<>(x -> x instanceof RAbstractRawVector, RAbstractRawVector.class));
+            return visit(new TypeFilter<>(RAbstractRawVector.class));
         } else {
             throw RInternalError.unimplemented("TODO: more types here");
         }
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/DefaultArgsExtractor.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/DefaultArgsExtractor.java
index cc63af538efe11861c189cf3399bd85babd03ae4..3b9c62f6dd6b6495a7f8b8d086e4c1a9cee5834e 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/DefaultArgsExtractor.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/DefaultArgsExtractor.java
@@ -61,13 +61,12 @@ class DefaultArgsExtractor {
         HashMap<String, Samples<?>> samplesMap = new HashMap<>();
         try {
 
-            Source source = RSource.fromTextInternal("formals(" + functionName + ")",
-                            RSource.Internal.UNIT_TEST);
+            Source source = RSource.fromTextInternal("formals(" + functionName + ")", RSource.Internal.UNIT_TEST);
 
             Value defArgVal = vm.eval(source);
 
-            if (defArgVal.get() instanceof RPairList) {
-                RPairList formals = (RPairList) defArgVal.get();
+            try {
+                RPairList formals = defArgVal.as(RPairList.class);
                 RStringVector names = formals.getNames();
 
                 for (int i = 0; i < names.getLength(); i++) {
@@ -77,8 +76,7 @@ class DefaultArgsExtractor {
                     if (defVal instanceof RLanguage) {
                         String deparsedDefVal = RDeparse.deparse(defVal);
                         try {
-                            Value eval = vm.eval(RSource.fromTextInternal(deparsedDefVal,
-                                            RSource.Internal.UNIT_TEST));
+                            Value eval = vm.eval(RSource.fromTextInternal(deparsedDefVal, RSource.Internal.UNIT_TEST));
                             defVal = eval.get();
                         } catch (Throwable t) {
                             printer.accept("Warning: Unable to evaluate the default value of argument " + name + ". Expression: " + deparsedDefVal);
@@ -107,6 +105,8 @@ class DefaultArgsExtractor {
                         samplesMap.put(name, Samples.anything(defVal));
                     }
                 }
+            } catch (ClassCastException e) {
+                // no pairlist...
             }
         } catch (Throwable t) {
             printer.accept("Warning: Unable to evaluate formal arguments of function " + functionName);
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/ForwardedValuesAnalyserTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/ForwardedValuesAnalyserTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..76fb3d04577b1188b8cbea518df1d6cc276afd4f
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/ForwardedValuesAnalyserTest.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.AndFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter.ScalarValue;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.DoubleFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.MissingFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.CoercionStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FilterStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FindFirstStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapIfStep;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardedValuesAnalyser;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingAnalysisResult;
+import com.oracle.truffle.r.runtime.RType;
+
+public class ForwardedValuesAnalyserTest {
+    @Test
+    public void testCoercion() {
+        PipelineStep<?, ?> firstStep = new CoercionStep<>(RType.Logical, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isLogicalForwarded());
+        assertTrue(result.isNullForwarded());
+        assertTrue(result.isMissingForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isStringForwarded());
+    }
+
+    @Test
+    public void testFindFirst() {
+        PipelineStep<?, ?> firstStep = new CoercionStep<>(RType.Character, false).setNext(new FindFirstStep<>("hello", String.class, null));
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isStringForwarded());
+        assertFalse(result.isLogicalForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+        assertFalse(result.isIntegerForwarded());
+    }
+
+    @Test
+    public void testRTypeFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new RTypeFilter<>(RType.Integer), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testTypeFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new TypeFilter<>(Integer.class), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testTypeFilterWithExtraCondition() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new TypeFilter<>(Integer.class, x -> x > 1), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testOrFilter1() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new OrFilter<>(new RTypeFilter<>(RType.Integer), new RTypeFilter<>(RType.Double)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertTrue(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testOrFilter2() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new OrFilter<>(new TypeFilter<>(Integer.class, x -> x > 1), new RTypeFilter<>(RType.Double)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.integerForwarded.isUnknown());
+        assertTrue(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testAndFilter1() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new AndFilter<>(new RTypeFilter<>(RType.Integer), new RTypeFilter<>(RType.Double)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testNot() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new AndFilter<>(new NotFilter<>(new RTypeFilter<>(RType.Integer)), new NotFilter<>(new RTypeFilter<>(RType.Double))), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isStringForwarded());
+        assertTrue(result.isComplexForwarded());
+        assertTrue(result.isNullForwarded());
+        assertTrue(result.isMissingForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isDoubleForwarded());
+    }
+
+    @Test
+    public void testAndFilter2() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new AndFilter<>(new TypeFilter<>(Integer.class, x -> x > 1), new TypeFilter<>(Integer.class, x -> x % 2 == 0)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testIntegerCoercionFollowedByFilterWithExtraCondition() {
+        PipelineStep<?, ?> firstStep = new CoercionStep<>(RType.Integer, false).setNext(new FindFirstStep<>(1, Integer.class, null)).setNext(
+                        new FilterStep<>(new TypeFilter<>(Integer.class, x -> x > 1), null, false));
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareScalarValueFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.ScalarValue(1, RType.Integer)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareNAValueFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.NATest(RType.Integer)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareStringLengthFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.StringLength(1)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.stringForwarded.isUnknown());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareEmptyVectorFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.VectorSize(0)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isIntegerForwarded());
+    }
+
+    @Test
+    public void testCompareOneElementVectorFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.VectorSize(1)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertTrue(result.isDoubleForwarded());
+        assertTrue(result.isIntegerForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareMoreElementsVectorFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.GE, new CompareFilter.VectorSize(2)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareMoreElementsVectorFilter2() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.LE, new CompareFilter.VectorSize(2)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertTrue(result.isDoubleForwarded());
+        assertTrue(result.isIntegerForwarded());
+        assertTrue(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareElementAt0Filter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.ElementAt(0, 1, RType.Integer)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareElementAt1Filter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.ElementAt(1, 1, RType.Integer)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testCompareDimFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new CompareFilter.Dim(0, 1)), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testDoubleFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(DoubleFilter.IS_FINITE, null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.doubleForwarded.isUnknown());
+        assertFalse(result.isIntegerForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testNotNullFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new NotFilter<>(NullFilter.INSTANCE), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertTrue(result.isDoubleForwarded());
+        assertTrue(result.isStringForwarded());
+        assertTrue(result.isMissingForwarded());
+        assertFalse(result.isNullForwarded());
+    }
+
+    @Test
+    public void testNotMissingFilter() {
+        PipelineStep<?, ?> firstStep = new FilterStep<>(new NotFilter<>(MissingFilter.INSTANCE), null, false);
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertTrue(result.isDoubleForwarded());
+        assertTrue(result.isStringForwarded());
+        assertTrue(result.isNullForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testNoBranchReturnIf() {
+        PipelineStep<?, ?> firstStep = new MapIfStep<>(NullFilter.INSTANCE, null, null, true).setNext(new FilterStep<>(new RTypeFilter<>(RType.Integer), null, false));
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isIntegerForwarded());
+        assertTrue(result.isNullForwarded());
+        assertFalse(result.isDoubleForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testReturnIfWithTrueBranch() {
+        //@formatter:off
+        PipelineStep<?, ?> firstStep = new MapIfStep<>(new RTypeFilter<>(RType.Integer),
+                        new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new ScalarValue(1, RType.Integer)), null, false), null, true).
+                        setNext(new FilterStep<>(new RTypeFilter<>(RType.Double), null, false));
+        //@formatter:on
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isDoubleForwarded());
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+
+    @Test
+    public void testReturnIfWithBothBranches() {
+        //@formatter:off
+        PipelineStep<?, ?> firstStep = new MapIfStep<>(new RTypeFilter<>(RType.Integer), // the condition
+                        // true branch
+                        new FilterStep<>(new CompareFilter<>(CompareFilter.EQ, new ScalarValue(1, RType.Integer)), null, false),
+                        // false branch
+                        new FilterStep<>(new RTypeFilter<>(RType.Double), null, false), true);
+        //@formatter:on
+
+        ForwardedValuesAnalyser fwdAn = new ForwardedValuesAnalyser();
+        ForwardingAnalysisResult result = fwdAn.analyse(firstStep);
+        assertTrue(result.isDoubleForwarded());
+        assertTrue(result.integerForwarded.isUnknown());
+        assertFalse(result.isNullForwarded());
+        assertFalse(result.isStringForwarded());
+        assertFalse(result.isMissingForwarded());
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
index e31dde44de60c70dff2dec4c18d88e74eabb0a4a..11c58387f483582624a1cb35361f476196d500de 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/PipelineToCastNodeTests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@ package com.oracle.truffle.r.nodes.test;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
 
+import java.util.Optional;
+
 import org.junit.Test;
 
 import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
@@ -98,7 +100,7 @@ public class PipelineToCastNodeTests {
 
     @Test
     public void mustBeREnvironmentAsIntegerVectorFindFirst() {
-        CastNode pipeline = createPipeline(new FilterStep<>(new TypeFilter<>(x -> x instanceof REnvironment, REnvironment.class), null, false).setNext(
+        CastNode pipeline = createPipeline(new FilterStep<>(new TypeFilter<>(REnvironment.class), null, false).setNext(
                         new CoercionStep<>(RType.Integer, false).setNext(new FindFirstStep<>("hello", String.class, null))));
         CastNode chain = assertBypassNode(pipeline);
         assertChainedCast(chain, ChainedCastNode.class, FindFirstNode.class);
@@ -126,6 +128,7 @@ public class PipelineToCastNodeTests {
 
     private static CastNode createPipeline(PipelineStep<?, ?> lastStep) {
         PipelineConfigBuilder configBuilder = new PipelineConfigBuilder("x");
-        return PipelineToCastNode.convert(configBuilder.build(), lastStep);
+        configBuilder.setValueForwarding(false);
+        return PipelineToCastNode.convert(configBuilder.build(), lastStep, Optional.empty());
     }
 }
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java
index 62a2998e3dcf351e6402798ea5cdb4d8e60dc3c5..e4b307888c9c0fb6bcbc1bca72dd0b34c6a0d82d 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/RBuiltinDiagnostics.java
@@ -94,6 +94,13 @@ public class RBuiltinDiagnostics {
     }
 
     public static void main(String[] args) throws Throwable {
+        // TODO: Enable it when the diagnostics is rewritten using CP-IR
+        if (true) {
+            System.out.println("Temporarily disabled until the diagnostics is rewritten using CP-IR");
+            return;
+        }
+
+        @SuppressWarnings("unused")
         RBuiltinDiagnostics rbDiag = ChimneySweepingSuite.createChimneySweepingSuite(args).orElseGet(() -> createRBuiltinDiagnostics(args));
 
         List<String> bNames = Arrays.stream(args).filter(arg -> !arg.startsWith("-")).collect(Collectors.toList());
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/BypassNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/BypassNodeGenSampler.java
index 255e3ea814ddfe15c4c0494cc49ee2cc6b12fd22..8ec4b0dc84d206a7fd9d692a726ff9f595062842 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/BypassNodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/BypassNodeGenSampler.java
@@ -48,8 +48,8 @@ public class BypassNodeGenSampler extends CastNodeSampler<BypassNodeGen> {
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputTypes) {
-        TypeExpr rt = wrappedHeadSampler == null ? TypeExpr.ANYTHING : wrappedHeadSampler.resultTypes(inputTypes);
+    public TypeExpr resultTypes(TypeExpr inputTypes, SamplingContext ctx) {
+        TypeExpr rt = wrappedHeadSampler == null ? TypeExpr.ANYTHING : wrappedHeadSampler.resultTypes(inputTypes, ctx);
         if (nullMapper != null) {
             rt = rt.or(nullMapper.resultTypes(inputTypes));
         } else {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastToVectorNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastToVectorNodeGenSampler.java
index 14e7e7d935012269d79ca4dfdb5a8f633099ad67..c493163b6412d5c2bcb7906e72569d08de0ddf4e 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastToVectorNodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastToVectorNodeGenSampler.java
@@ -44,7 +44,7 @@ public class CastToVectorNodeGenSampler extends CastNodeSampler<CastToVectorNode
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputType) {
+    public TypeExpr resultTypes(TypeExpr inputType, SamplingContext ctx) {
         List<Cast> castList;
         if (castNode.isPreserveNonVector()) {
             castList = Arrays.asList(new Cast(RNull.class, RNull.class),
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ChainedCastNodeSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ChainedCastNodeSampler.java
index 2ea68618a3864c93e3bd8258ace1713fd2b85902..d2a01b173dac7a46cd17a6eb65c0c7561c0727a9 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ChainedCastNodeSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ChainedCastNodeSampler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,8 +39,8 @@ public final class ChainedCastNodeSampler extends CastNodeSampler<ChainedCastNod
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputTypes) {
-        return secondCast.resultTypes(firstCast.resultTypes(inputTypes));
+    public TypeExpr resultTypes(TypeExpr inputTypes, SamplingContext ctx) {
+        return secondCast.resultTypes(firstCast.resultTypes(inputTypes, ctx), ctx);
     }
 
     @Override
@@ -50,7 +50,7 @@ public final class ChainedCastNodeSampler extends CastNodeSampler<ChainedCastNod
 
     @Override
     public Samples<?> collectSamples(TypeExpr inputTypes, Samples<?> downStreamSamples) {
-        TypeExpr rt1 = firstCast.resultTypes(inputTypes);
+        TypeExpr rt1 = firstCast.resultTypes(inputTypes, new SamplingContext());
         return firstCast.collectSamples(inputTypes, secondCast.collectSamples(rt1, downStreamSamples));
     }
 }
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNodeGenSampler.java
index 8ccde29473c2c72881f9b4546e677fba8a51dfe7..3b8a88b0170a86fe063aae145449dcae7b0dc21a 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNodeGenSampler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,17 +42,26 @@ public class ConditionalMapNodeGenSampler extends CastNodeSampler<ConditionalMap
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputType) {
-        return trueBranchResultTypes(inputType).or(falseBranchResultTypes(inputType));
+    public TypeExpr resultTypes(TypeExpr inputType, SamplingContext ctx) {
+        if (castNode.isReturns()) {
+            ctx.addAltResultType(trueBranchResultTypes(inputType, ctx));
+            return falseBranchResultTypes(inputType, ctx);
+        } else {
+            return trueBranchResultTypes(inputType, ctx).or(falseBranchResultTypes(inputType, ctx));
+        }
     }
 
-    private TypeExpr trueBranchResultTypes(TypeExpr inputType) {
-        return trueBranch.resultTypes(argFilter.trueBranchType().and(inputType));
+    private TypeExpr trueBranchResultTypes(TypeExpr inputType, SamplingContext ctx) {
+        if (trueBranch != null) {
+            return trueBranch.resultTypes(argFilter.trueBranchType().and(inputType), ctx);
+        } else {
+            return argFilter.trueBranchType().and(inputType);
+        }
     }
 
-    private TypeExpr falseBranchResultTypes(TypeExpr inputType) {
+    private TypeExpr falseBranchResultTypes(TypeExpr inputType, SamplingContext ctx) {
         if (falseBranch != null) {
-            return falseBranch.resultTypes(argFilter.falseBranchType().and(inputType));
+            return falseBranch.resultTypes(argFilter.falseBranchType().and(inputType), ctx);
         } else {
             return argFilter.falseBranchType().and(inputType);
         }
@@ -60,8 +69,8 @@ public class ConditionalMapNodeGenSampler extends CastNodeSampler<ConditionalMap
 
     @Override
     public Samples<?> collectSamples(TypeExpr inputType, Samples<?> downStreamSamples) {
-        TypeExpr trueBranchResultType = trueBranchResultTypes(inputType);
-        TypeExpr falseBranchResultType = falseBranchResultTypes(inputType);
+        TypeExpr trueBranchResultType = trueBranchResultTypes(inputType, new SamplingContext());
+        TypeExpr falseBranchResultType = falseBranchResultTypes(inputType, new SamplingContext());
 
         // filter out the incompatible samples
         Samples compatibleTrueBranchDownStreamSamples = downStreamSamples.filter(x -> trueBranchResultType.isInstance(x));
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java
index c4f488fc00c49189f157885f749f29c7dfbf8c4c..4a73a29cce796b9c4de37d7120fb19c116a28523 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,7 @@ public class FilterNodeGenSampler extends CastNodeSampler<FilterNodeGen> {
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputType) {
+    public TypeExpr resultTypes(TypeExpr inputType, SamplingContext ctx) {
         if (isWarning) {
             return inputType;
         } else {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java
index a7a41d91c8a2f63d23e2bccd654949a522adfa36..2135903ab21d91d006f2b82824b22752ac89448c 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java
@@ -113,7 +113,7 @@ public class FindFirstNodeGenSampler extends CastNodeSampler<FindFirstNodeGen> {
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputType) {
+    public TypeExpr resultTypes(TypeExpr inputType, SamplingContext ctx) {
         TypeExpr rt;
         if (elementClass == null || elementClass == Object.class) {
             if (inputType.isAnything()) {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/MapNodeSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/MapNodeSampler.java
index 3a62d8e3f158ca13982bcc7655a0f5ff507d7ffd..079c4090a1b794021b4167a0ae747e9e5fbba406 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/MapNodeSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/MapNodeSampler.java
@@ -39,7 +39,7 @@ public class MapNodeSampler extends CastNodeSampler<MapNode> {
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputTypes) {
+    public TypeExpr resultTypes(TypeExpr inputTypes, SamplingContext ctx) {
         return mapFn.resultTypes(inputTypes);
     }
 
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/NonNANodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/NonNANodeGenSampler.java
index 41d275152e506aa33a8f99129ad43a668e190388..3f2f805208270c2e745f75310873ffcb433ce6e9 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/NonNANodeGenSampler.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/NonNANodeGenSampler.java
@@ -44,7 +44,7 @@ public class NonNANodeGenSampler extends CastNodeSampler<NonNANodeGen> {
     }
 
     @Override
-    public TypeExpr resultTypes(TypeExpr inputType) {
+    public TypeExpr resultTypes(TypeExpr inputType, SamplingContext ctx) {
         return inputType;
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
index 6e2a429df7de0232229a2e0536f1a2e0b900471f..40622acfcd336e3a7bc0662778064ffae88c57bd 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
@@ -71,14 +71,14 @@ public abstract class InlineCacheNode extends RBaseNode {
         } else {
             vf = SubstituteVirtualFrame.create(frame.materialize());
         }
-        return reified.execute(vf);
+        return reified.visibleExecute(vf);
     }
 
     protected RNode cache(Object value) {
         return RASTUtils.cloneNode(reify.apply(value));
     }
 
-    @Specialization(contains = "doCached")
+    @Specialization(replaces = "doCached")
     protected Object doGeneric(Frame frame, Object value) {
         return generic.apply(frame, value);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
index 21a4e1293a6cecd42faaa778194bc48c1d43944a..2b3bbc78a7ea4c918f19177824499d8017c458da 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -134,7 +134,7 @@ public class RASTUtils {
      * variables and actual values for constants.
      */
     @TruffleBoundary
-    public static Object createLanguageElement(RSyntaxNode element) {
+    public static Object createLanguageElement(RSyntaxElement element) {
         assert element != null;
         if (element instanceof RSyntaxConstant) {
             Object value = ((RSyntaxConstant) element).getValue();
@@ -149,7 +149,7 @@ public class RASTUtils {
             return RDataFactory.createSymbol(id);
         } else {
             assert element instanceof RSyntaxCall || element instanceof RSyntaxFunction;
-            return RDataFactory.createLanguage(element.asRNode());
+            return RDataFactory.createLanguage(((RSyntaxNode) element).asRNode());
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
index d14ca391d6f5f2769f9e33b7aec0ee35340bb286..535ed30b70b737426d63326036b21181d04570f5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@ import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.function.opt.EagerEvalHelper;
 import com.oracle.truffle.r.nodes.function.opt.OptConstantPromiseNode;
 import com.oracle.truffle.r.nodes.function.opt.OptVariablePromiseBaseNode;
+import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.REmpty;
 import com.oracle.truffle.r.runtime.data.RMissing;
@@ -56,8 +57,6 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
  */
 public final class AccessArgumentNode extends RNode {
 
-    @Child private ReadArgumentNode readArgNode;
-
     @Child private PromiseHelperNode promiseHelper;
 
     /**
@@ -65,10 +64,6 @@ public final class AccessArgumentNode extends RNode {
      */
     private final int index;
 
-    public ReadArgumentNode getReadArgNode() {
-        return readArgNode;
-    }
-
     /**
      * Used to cache {@link RPromise} evaluations.
      */
@@ -84,7 +79,6 @@ public final class AccessArgumentNode extends RNode {
 
     private AccessArgumentNode(int index) {
         this.index = index;
-        this.readArgNode = new ReadArgumentNode(index);
     }
 
     public static AccessArgumentNode create(int index) {
@@ -100,7 +94,7 @@ public final class AccessArgumentNode extends RNode {
 
     @Override
     public Object execute(VirtualFrame frame) {
-        return doArgument(frame, readArgNode.execute(frame));
+        return doArgument(frame, RArguments.getArgument(frame, index));
     }
 
     @Override
@@ -129,6 +123,10 @@ public final class AccessArgumentNode extends RNode {
     }
 
     private Object doArgument(VirtualFrame frame, Object arg) {
+        if (arg == null) {
+            CompilerDirectives.transferToInterpreter();
+            throw RInternalError.shouldNotReachHere("null argument in slot " + index + " of " + getRootNode());
+        }
         if (hasDefaultArg) {
             if (isMissingProfile.profile(arg == RMissing.instance) || isEmptyProfile.profile(arg == REmpty.instance)) {
                 return doArgumentInternal(frame);
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 8d211627165870f0b6c0ec426ca10c558e34988b..2a5d3799e858c13015f210bfb9ee92d2277f93db 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
@@ -15,8 +15,6 @@ package com.oracle.truffle.r.nodes.access;
 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.NodeChild;
-import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
@@ -39,15 +37,14 @@ 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;
-import com.oracle.truffle.r.runtime.nodes.RNode;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 // Transcribed from src/main/attrib.c file (R_do_slot function)
 
 /**
  * Perform a slot access. This node represents the {@code @} operator in R.
  */
-@NodeChildren({@NodeChild(value = "object", type = RNode.class), @NodeChild(value = "name", type = RNode.class)})
-public abstract class AccessSlotNode extends RNode {
+public abstract class AccessSlotNode extends RBaseNode {
 
     public abstract Object executeAccess(Object o, String name);
 
@@ -128,9 +125,8 @@ public abstract class AccessSlotNode extends RNode {
         return (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, f);
     }
 
-    @SuppressWarnings("unused")
     @Specialization(guards = {"!slotAccessAllowed(object)", "isDotData(name)"})
-    protected Object getSlotNonS4(RAttributable object, String name) {
+    protected Object getSlotNonS4(RAttributable object, @SuppressWarnings("unused") String name) {
         // TODO: any way to cache it or use a mechanism similar to overrides?
         REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods");
         RFunction dataPart = getDataPartFunction(methodsNamespace);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
index 52fa750d0304b0ce0fe55c97cf23214a8cde5e7f..24f773ecefd8797ac57073bf5f97e2ad202c743b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,6 @@ package com.oracle.truffle.r.nodes.access;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.dsl.NodeChild;
-import com.oracle.truffle.api.dsl.NodeField;
-import com.oracle.truffle.api.dsl.NodeFields;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotKind;
@@ -38,7 +36,6 @@ import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
 @NodeChild(value = "rhs", type = RNode.class)
-@NodeFields({@NodeField(name = "name", type = Object.class)})
 /**
  * Common code/state for all the variants of {@code WriteVariableNode}. At this level, we just have
  * a {@code name} for the variable and expression {@code rhs} to be assigned to.
@@ -47,6 +44,10 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
  */
 abstract class BaseWriteVariableNode extends WriteVariableNode {
 
+    protected BaseWriteVariableNode(Object name) {
+        super(name);
+    }
+
     private final ConditionProfile isObjectProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile isCurrentProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile isShareableProfile = ConditionProfile.createBinaryProfile();
@@ -120,22 +121,23 @@ abstract class BaseWriteVariableNode extends WriteVariableNode {
         }
     }
 
-    @SuppressWarnings("unused")
-    protected boolean isLogicalKind(Frame frame, FrameSlot frameSlot) {
+    /*
+     * The frame parameters are needed to keep the guards from being considered static.
+     */
+
+    protected boolean isLogicalKind(@SuppressWarnings("unused") Frame frame, FrameSlot frameSlot) {
         return isKind(frameSlot, FrameSlotKind.Boolean);
     }
 
-    @SuppressWarnings("unused")
-    protected boolean isIntegerKind(Frame frame, FrameSlot frameSlot) {
+    protected boolean isIntegerKind(@SuppressWarnings("unused") Frame frame, FrameSlot frameSlot) {
         return isKind(frameSlot, FrameSlotKind.Int);
     }
 
-    @SuppressWarnings("unused")
-    protected boolean isDoubleKind(Frame frame, FrameSlot frameSlot) {
+    protected boolean isDoubleKind(@SuppressWarnings("unused") Frame frame, FrameSlot frameSlot) {
         return isKind(frameSlot, FrameSlotKind.Double);
     }
 
-    private boolean isKind(FrameSlot frameSlot, FrameSlotKind kind) {
+    protected boolean isKind(FrameSlot frameSlot, FrameSlotKind kind) {
         if (frameSlot.getKind() == kind) {
             return true;
         } else {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java
index 9cdd88d0e8cf8f593d065e8b41898c8b51a60114..5a339754ec551d8e7662588b2d10f897371918e0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.access;
 
 import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.source.SourceSection;
@@ -39,7 +40,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 public abstract class ConstantNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxConstant {
 
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     private ConstantNode(SourceSection sourceSection) {
         super(sourceSection);
@@ -60,13 +61,23 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
     @Override
     public abstract Object getValue();
 
-    protected final void handleVisibility(VirtualFrame frame) {
-        visibility.execute(frame, true);
+    @Override
+    public final void voidExecute(VirtualFrame frame) {
+        // nothing to do
     }
 
     @Override
     public final Object execute(VirtualFrame frame) {
-        handleVisibility(frame);
+        return getValue();
+    }
+
+    @Override
+    public final Object visibleExecute(VirtualFrame frame) {
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
         return getValue();
     }
 
@@ -113,7 +124,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
 
         @Override
         public double executeDouble(VirtualFrame frame) {
-            handleVisibility(frame);
             return doubleValue;
         }
     }
@@ -136,7 +146,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
 
         @Override
         public byte executeByte(VirtualFrame frame) {
-            handleVisibility(frame);
             return logicalValue;
         }
     }
@@ -159,7 +168,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
 
         @Override
         public int executeInteger(VirtualFrame frame) {
-            handleVisibility(frame);
             return intValue;
         }
     }
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 9f5e173e2d8419a5529513d5399c55e35dd33c11..4cd1ffa866ada9f3ed5cb3396c0ca55b103a22d6 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
@@ -14,8 +14,6 @@ package com.oracle.truffle.r.nodes.access;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
-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.InitAttributesNode;
@@ -28,12 +26,11 @@ import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.nodes.RNode;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 // 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 {
+public abstract class UpdateSlotNode extends RBaseNode {
 
     public abstract Object executeUpdate(Object object, String name, Object value);
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java
index f94e28dd3dc63d4ea88a7bd2542ec971c03804d8..8823779fd2583117c0daf220eaaf3c6dbacba15b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,116 +22,73 @@
  */
 package com.oracle.truffle.r.nodes.access;
 
-import static com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.findOrAddFrameSlot;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.dsl.NodeField;
-import com.oracle.truffle.api.dsl.NodeFields;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotKind;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.NodeCost;
-import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNodeFactory.ResolvedWriteLocalFrameVariableNodeGen;
-import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNodeFactory.UnresolvedWriteLocalFrameVariableNodeGen;
-import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
 /**
  * {@link WriteLocalFrameVariableNode} captures a write to the "local", i.e., current, frame. There
  * are several clients capturing different "kinds" of writes to the frame, e.g. saving an argument,
- * a source-level write, a a write helper for another source node (e.g. {@code ForNode}.
- *
- * The state starts out a "unresolved" and transforms to "resolved".
+ * a source-level write, a a write helper for another source node (e.g. {@code ForNode}).
  */
+@ImportStatic(FrameSlotKind.class)
 public abstract class WriteLocalFrameVariableNode extends BaseWriteVariableNode {
 
-    public abstract Mode getMode();
-
-    public static WriteLocalFrameVariableNode create(String name, RNode rhs, Mode mode) {
-        return UnresolvedWriteLocalFrameVariableNodeGen.create(rhs, name, mode);
+    public static WriteLocalFrameVariableNode create(Object name, Mode mode, RNode rhs) {
+        return WriteLocalFrameVariableNodeGen.create(name, mode, rhs);
     }
 
     public static WriteLocalFrameVariableNode createForRefCount(Object name) {
-        return UnresolvedWriteLocalFrameVariableNodeGen.create(null, name, Mode.INVISIBLE);
+        return WriteLocalFrameVariableNodeGen.create(name, Mode.INVISIBLE, null);
     }
 
-    @NodeField(name = "mode", type = Mode.class)
-    @NodeInfo(cost = NodeCost.UNINITIALIZED)
-    abstract static class UnresolvedWriteLocalFrameVariableNode extends WriteLocalFrameVariableNode {
-
-        @Specialization
-        protected byte doLogical(VirtualFrame frame, byte value) {
-            resolveAndSet(frame, value, FrameSlotKind.Byte);
-            return value;
-        }
-
-        @Specialization
-        protected int doInteger(VirtualFrame frame, int value) {
-            resolveAndSet(frame, value, FrameSlotKind.Int);
-            return value;
-        }
-
-        @Specialization
-        protected double doDouble(VirtualFrame frame, double value) {
-            resolveAndSet(frame, value, FrameSlotKind.Double);
-            return value;
-        }
+    public final Mode mode;
 
-        @Specialization
-        protected Object doObject(VirtualFrame frame, Object value) {
-            resolveAndSet(frame, value, FrameSlotKind.Object);
-            return value;
-        }
+    private final ValueProfile storedObjectProfile = ValueProfile.createClassProfile();
+    private final BranchProfile invalidateProfile = BranchProfile.create();
 
-        private void resolveAndSet(VirtualFrame frame, Object value, FrameSlotKind initialKind) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            // it's slow path (unconditional replace) so toString() is fine as well
-            if (getName().toString().isEmpty()) {
-                throw RError.error(RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE);
-            }
-            FrameSlot frameSlot = findOrAddFrameSlot(frame.getFrameDescriptor(), getName(), initialKind);
-            replace(ResolvedWriteLocalFrameVariableNode.create(getRhs(), getName(), frameSlot, getMode())).execute(frame, value);
-        }
+    protected WriteLocalFrameVariableNode(Object name, Mode mode) {
+        super(name);
+        this.mode = mode;
     }
 
-    @NodeFields({@NodeField(name = "frameSlot", type = FrameSlot.class), @NodeField(name = "mode", type = Mode.class)})
-    abstract static class ResolvedWriteLocalFrameVariableNode extends WriteLocalFrameVariableNode {
-
-        private final ValueProfile storedObjectProfile = ValueProfile.createClassProfile();
-        private final BranchProfile invalidateProfile = BranchProfile.create();
-
-        private static ResolvedWriteLocalFrameVariableNode create(RNode rhs, Object name, FrameSlot frameSlot, Mode mode) {
-            return ResolvedWriteLocalFrameVariableNodeGen.create(rhs, name, frameSlot, mode);
-        }
+    protected FrameSlot findOrAddFrameSlot(VirtualFrame frame, FrameSlotKind initialKind) {
+        return FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), getName(), initialKind);
+    }
 
-        @Specialization(guards = "isLogicalKind(frame, frameSlot)")
-        protected byte doLogical(VirtualFrame frame, FrameSlot frameSlot, byte value) {
-            FrameSlotChangeMonitor.setByteAndInvalidate(frame, frameSlot, value, false, invalidateProfile);
-            return value;
-        }
+    @Specialization(guards = "isLogicalKind(frame, frameSlot)")
+    protected byte doLogical(VirtualFrame frame, byte value,
+                    @Cached("findOrAddFrameSlot(frame, Byte)") FrameSlot frameSlot) {
+        FrameSlotChangeMonitor.setByteAndInvalidate(frame, frameSlot, value, false, invalidateProfile);
+        return value;
+    }
 
-        @Specialization(guards = "isIntegerKind(frame, frameSlot)")
-        protected int doInteger(VirtualFrame frame, FrameSlot frameSlot, int value) {
-            FrameSlotChangeMonitor.setIntAndInvalidate(frame, frameSlot, value, false, invalidateProfile);
-            return value;
-        }
+    @Specialization(guards = "isIntegerKind(frame, frameSlot)")
+    protected int doInteger(VirtualFrame frame, int value,
+                    @Cached("findOrAddFrameSlot(frame, Int)") FrameSlot frameSlot) {
+        FrameSlotChangeMonitor.setIntAndInvalidate(frame, frameSlot, value, false, invalidateProfile);
+        return value;
+    }
 
-        @Specialization(guards = "isDoubleKind(frame, frameSlot)")
-        protected double doDouble(VirtualFrame frame, FrameSlot frameSlot, double value) {
-            FrameSlotChangeMonitor.setDoubleAndInvalidate(frame, frameSlot, value, false, invalidateProfile);
-            return value;
-        }
+    @Specialization(guards = "isDoubleKind(frame, frameSlot)")
+    protected double doDouble(VirtualFrame frame, double value,
+                    @Cached("findOrAddFrameSlot(frame, Double)") FrameSlot frameSlot) {
+        FrameSlotChangeMonitor.setDoubleAndInvalidate(frame, frameSlot, value, false, invalidateProfile);
+        return value;
+    }
 
-        @Specialization
-        protected Object doObject(VirtualFrame frame, FrameSlot frameSlot, Object value) {
-            Object newValue = shareObjectValue(frame, frameSlot, storedObjectProfile.profile(value), getMode(), false);
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, frameSlot, newValue, false, invalidateProfile);
-            return value;
-        }
+    @Specialization
+    protected Object doObject(VirtualFrame frame, Object value,
+                    @Cached("findOrAddFrameSlot(frame, Object)") FrameSlot frameSlot) {
+        Object newValue = shareObjectValue(frame, frameSlot, storedObjectProfile.profile(value), mode, false);
+        FrameSlotChangeMonitor.setObjectAndInvalidate(frame, frameSlot, newValue, false, invalidateProfile);
+        return value;
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java
index c3d06849facec7118352a5eab003a85c99aa40af..8d5de24ba4a73eccd47637e876f98e21dbec25e5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperFrameVariableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@ import static com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.find
 
 import com.oracle.truffle.api.CompilerDirectives;
 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.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotKind;
@@ -35,10 +34,8 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 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.access.WriteLocalFrameVariableNodeFactory.UnresolvedWriteLocalFrameVariableNodeGen;
 import com.oracle.truffle.r.nodes.access.WriteSuperFrameVariableNodeFactory.ResolvedWriteSuperFrameVariableNodeGen;
 import com.oracle.truffle.r.runtime.RArguments;
-import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -50,8 +47,12 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
  */
 abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
 
-    static WriteVariableNode create(String name, RNode rhs, Mode mode) {
-        return new UnresolvedWriteSuperFrameVariableNode(name, rhs, mode);
+    protected WriteSuperFrameVariableNode(Object name) {
+        super(name);
+    }
+
+    static WriteVariableNode create(String name, Mode mode, RNode rhs) {
+        return new UnresolvedWriteSuperFrameVariableNode(name, mode, rhs);
     }
 
     protected abstract void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame);
@@ -63,7 +64,8 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
         return value;
     }
 
-    @NodeChildren({@NodeChild(value = "enclosingFrame", type = AccessEnclosingFrameNode.class), @NodeChild(value = "frameSlotNode", type = FrameSlotNode.class)})
+    @NodeChild(value = "enclosingFrame", type = AccessEnclosingFrameNode.class)
+    @NodeChild(value = "frameSlotNode", type = FrameSlotNode.class)
     protected abstract static class ResolvedWriteSuperFrameVariableNode extends WriteSuperFrameVariableNode {
 
         private final ValueProfile storedObjectProfile = ValueProfile.createClassProfile();
@@ -72,7 +74,8 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
 
         private final Mode mode;
 
-        public ResolvedWriteSuperFrameVariableNode(Mode mode) {
+        public ResolvedWriteSuperFrameVariableNode(Object name, Mode mode) {
+            super(name);
             this.mode = mode;
         }
 
@@ -105,18 +108,12 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
 
         @Child private RNode rhs;
 
-        private final String name;
         private final Mode mode;
 
-        UnresolvedWriteSuperFrameVariableNode(String name, RNode rhs, Mode mode) {
-            this.rhs = rhs;
-            this.name = name;
+        UnresolvedWriteSuperFrameVariableNode(Object name, Mode mode, RNode rhs) {
+            super(name);
             this.mode = mode;
-        }
-
-        @Override
-        public String getName() {
-            return name;
+            this.rhs = rhs;
         }
 
         @Override
@@ -127,9 +124,6 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
         @Override
         public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            if (name.isEmpty()) {
-                throw RError.error(RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE);
-            }
             final WriteSuperFrameVariableNode writeNode;
             if (REnvironment.isGlobalEnvFrame(enclosingFrame)) {
                 /*
@@ -137,11 +131,11 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
                  * in the chain, needs the rhs and enclosingFrame nodes
                  */
                 AccessEnclosingFrameNode enclosingFrameNode = RArguments.getEnclosingFrame(frame) == enclosingFrame ? new AccessEnclosingFrameNode() : null;
-                writeNode = ResolvedWriteSuperFrameVariableNodeGen.create(mode, rhs, enclosingFrameNode,
-                                FrameSlotNode.create(findOrAddFrameSlot(enclosingFrame.getFrameDescriptor(), name, FrameSlotKind.Illegal)), name);
+                writeNode = ResolvedWriteSuperFrameVariableNodeGen.create(getName(), mode, rhs, enclosingFrameNode,
+                                FrameSlotNode.create(findOrAddFrameSlot(enclosingFrame.getFrameDescriptor(), getName(), FrameSlotKind.Illegal)));
             } else {
-                ResolvedWriteSuperFrameVariableNode actualWriteNode = ResolvedWriteSuperFrameVariableNodeGen.create(mode, null, null, FrameSlotNode.create(name), name);
-                writeNode = new WriteSuperFrameVariableConditionalNode(actualWriteNode, new UnresolvedWriteSuperFrameVariableNode(name, null, mode), rhs);
+                ResolvedWriteSuperFrameVariableNode actualWriteNode = ResolvedWriteSuperFrameVariableNodeGen.create(getName(), mode, null, null, FrameSlotNode.createTemp(getName(), false));
+                writeNode = new WriteSuperFrameVariableConditionalNode(getName(), actualWriteNode, new UnresolvedWriteSuperFrameVariableNode(getName(), mode, null), rhs);
             }
             replace(writeNode).execute(frame, value, enclosingFrame);
         }
@@ -154,7 +148,7 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
                 execute(frame, value, enclosingFrame);
             } else {
                 // we're in global scope, do a local write instead
-                replace(UnresolvedWriteLocalFrameVariableNodeGen.create(rhs, name, mode)).execute(frame, value);
+                replace(WriteLocalFrameVariableNode.create(getName(), mode, rhs)).execute(frame, value);
             }
         }
     }
@@ -169,17 +163,13 @@ abstract class WriteSuperFrameVariableNode extends BaseWriteVariableNode {
         private final ConditionProfile hasValueProfile = ConditionProfile.createBinaryProfile();
         private final ConditionProfile nullSuperFrameProfile = ConditionProfile.createBinaryProfile();
 
-        WriteSuperFrameVariableConditionalNode(ResolvedWriteSuperFrameVariableNode writeNode, WriteSuperFrameVariableNode nextNode, RNode rhs) {
+        WriteSuperFrameVariableConditionalNode(Object name, ResolvedWriteSuperFrameVariableNode writeNode, WriteSuperFrameVariableNode nextNode, RNode rhs) {
+            super(name);
             this.writeNode = writeNode;
             this.nextNode = nextNode;
             this.rhs = rhs;
         }
 
-        @Override
-        public Object getName() {
-            return writeNode.getName();
-        }
-
         @Override
         public RNode getRhs() {
             return rhs;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java
index d8bd5afed82b97de816a820eeb98558be298999c..9416b60d27eb77218c865980578d564b9467816f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,15 @@ public abstract class WriteVariableNode extends RNode {
         INVISIBLE
     }
 
-    public abstract Object getName();
+    private final Object name;
+
+    protected WriteVariableNode(Object name) {
+        this.name = name;
+    }
+
+    public final Object getName() {
+        return name;
+    }
 
     public abstract RNode getRhs();
 
@@ -54,27 +62,27 @@ public abstract class WriteVariableNode extends RNode {
      */
     public static WriteVariableNode createArgSave(String name, RNode rhs) {
         if (FastROptions.InvisibleArgs.getBooleanValue()) {
-            return WriteLocalFrameVariableNode.create(name, rhs, Mode.INVISIBLE);
+            return WriteLocalFrameVariableNode.create(name, Mode.INVISIBLE, rhs);
         } else {
-            return WriteLocalFrameVariableNode.create(name, rhs, Mode.REGULAR);
+            return WriteLocalFrameVariableNode.create(name, Mode.REGULAR, rhs);
         }
     }
 
     /**
      * Variant for anonymous variables in the current frame.
      */
-    public static WriteVariableNode createAnonymous(String name, RNode rhs, Mode mode) {
-        return WriteLocalFrameVariableNode.create(name, rhs, mode);
+    public static WriteVariableNode createAnonymous(String name, Mode mode, RNode rhs) {
+        return WriteLocalFrameVariableNode.create(name, mode, rhs);
     }
 
     /**
      * Variant for anonymous variables in either the current or a super frame..
      */
-    public static WriteVariableNode createAnonymous(String name, RNode rhs, Mode mode, boolean isSuper) {
+    public static WriteVariableNode createAnonymous(String name, Mode mode, RNode rhs, boolean isSuper) {
         if (isSuper) {
-            return WriteSuperFrameVariableNode.create(name, rhs, mode);
+            return WriteSuperFrameVariableNode.create(name, mode, rhs);
         } else {
-            return WriteLocalFrameVariableNode.create(name, rhs, mode);
+            return WriteLocalFrameVariableNode.create(name, mode, rhs);
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java
index a442c0747aaadaea588b038453ad86d93c88f499..39542472910f4529d511bcf59386ff89df3bb67d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,53 +24,69 @@ package com.oracle.truffle.r.nodes.access;
 
 import static com.oracle.truffle.api.nodes.NodeCost.NONE;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.NodeInfo;
+import com.oracle.truffle.api.nodes.UnexpectedResultException;
 import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode.Mode;
 import com.oracle.truffle.r.nodes.control.OperatorNode;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 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.nodes.RNode;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 
+/**
+ * This node represents a write to a variable on the syntax level, i.e., in the R source code.
+ */
 @NodeInfo(cost = NONE)
 public final class WriteVariableSyntaxNode extends OperatorNode {
 
     @Child private WriteVariableNode write;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     private final RSyntaxElement lhs;
 
-    public WriteVariableSyntaxNode(SourceSection source, RSyntaxLookup operator, RSyntaxElement lhs, RNode rhs, boolean isSuper) {
+    public WriteVariableSyntaxNode(SourceSection source, RSyntaxLookup operator, RSyntaxElement lhs, String name, RNode rhs, boolean isSuper) {
         super(source, operator);
         this.lhs = lhs;
-        String name;
-        if (lhs instanceof RSyntaxLookup) {
-            name = ((RSyntaxLookup) lhs).getIdentifier();
-        } else if (lhs instanceof RSyntaxConstant) {
-            RSyntaxConstant c = (RSyntaxConstant) lhs;
-            if (c.getValue() instanceof String) {
-                name = (String) c.getValue();
-            } else {
-                // "this" needs to be initialized for error reporting to work
-                this.write = WriteVariableNode.createAnonymous("dummy", rhs, Mode.REGULAR, isSuper);
-                throw RError.error(this, RError.Message.INVALID_LHS, "do_set");
-            }
-        } else {
-            throw RInternalError.unimplemented("unexpected lhs type in replacement: " + lhs.getClass());
-        }
-        this.write = WriteVariableNode.createAnonymous(name, rhs, Mode.REGULAR, isSuper);
+        this.write = WriteVariableNode.createAnonymous(name, Mode.REGULAR, rhs, isSuper);
         assert write != null;
     }
 
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        write.execute(frame);
+    }
+
     @Override
     public Object execute(VirtualFrame frame) {
+        return write.execute(frame);
+    }
+
+    @Override
+    public int executeInteger(VirtualFrame frame) throws UnexpectedResultException {
+        return write.executeInteger(frame);
+    }
+
+    @Override
+    public double executeDouble(VirtualFrame frame) throws UnexpectedResultException {
+        return write.executeDouble(frame);
+    }
+
+    @Override
+    public byte executeByte(VirtualFrame frame) throws UnexpectedResultException {
+        return write.executeByte(frame);
+    }
+
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
         Object result = write.execute(frame);
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
         visibility.execute(frame, false);
         return result;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
index cf0585f4b13e7078466524a68b3ae09b79fbbb28..990fdbfe45be1c4e6996ccfc478b4d4a008d3c6b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -125,7 +125,7 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
 
     @Child private PromiseHelperNode promiseHelper;
     @Child private CheckTypeNode checkTypeNode;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     @CompilationFinal private FrameLevel read;
     @CompilationFinal private boolean needsCopying;
@@ -167,20 +167,34 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
         return identifier instanceof String;
     }
 
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        executeInternal(frame, frame);
+    }
+
     @Override
     public Object execute(VirtualFrame frame) {
-        return executeInternal(frame, kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(frame)) : frame);
+        return executeInternal(frame, frame);
+    }
+
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
+        assert kind != ReadKind.Silent;
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
+        return executeInternal(frame, frame);
     }
 
     public Object execute(VirtualFrame frame, Frame variableFrame) {
         assert frame != null;
-        return executeInternal(frame, kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(variableFrame)) : variableFrame);
+        return executeInternal(frame, variableFrame);
     }
 
-    private Object executeInternal(VirtualFrame frame, Frame variableFrame) {
-        if (kind != ReadKind.Silent) {
-            visibility.execute(frame, true);
-        }
+    private Object executeInternal(VirtualFrame frame, Frame initialFrame) {
+        Frame variableFrame = kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(initialFrame)) : initialFrame;
 
         Object result;
         if (read == null) {
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 a1905a771a8c5eee723c38df14953c62796c8497..a1447c00d9c472a11467a1a0189abf7c88da08ba 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
@@ -273,7 +273,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
     private Object extract(int dimensionIndex, RAbstractStringVector vector, Object pos, PositionProfile profile) {
         if (extractDimNames == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            extractDimNames = new ExtractDimNamesNode(numberOfDimensions);
+            extractDimNames = insert(new ExtractDimNamesNode(numberOfDimensions));
         }
         return extractDimNames.extract(dimensionIndex, vector, pos, profile);
     }
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 5838aa1f2edde01f6e59c800eb8ccefff2d03a5b..6e7fff3d2d83c7fd85d9fbb98b08e68f554be945 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
@@ -396,7 +396,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
             return RType.maxPrecedence(value, vector);
         } else if (vector.isNull() || value.isNull()) {
             if (!value.isNull()) {
-                return value;
+                return (mode == ElementAccessMode.FIELD_SUBSCRIPT) ? RType.List : value;
             }
             if (mode.isSubscript() && numberOfDimensions > 1) {
                 return null;
@@ -494,7 +494,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode {
             return cachedValue;
         }
 
-        @Specialization(contains = "profile")
+        @Specialization(replaces = "profile")
         protected static boolean generic(boolean value) {
             return value;
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ElementAccessMode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ElementAccessMode.java
index eb7a6003aeb220c2e58650efe0dab8c4917be87d..0365dbe31ae8d30721a70d5bdf451fe166e5c7f3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ElementAccessMode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ElementAccessMode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,9 @@ public enum ElementAccessMode {
     /* x[[a]] */
     SUBSCRIPT,
 
+    /* x$a */
+    FIELD_SUBSCRIPT,
+
     /* x[a] */
     SUBSET;
 
@@ -38,6 +41,6 @@ public enum ElementAccessMode {
     }
 
     public boolean isSubscript() {
-        return this == SUBSCRIPT;
+        return this == SUBSCRIPT || this == FIELD_SUBSCRIPT;
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java
index 9d20e403c3a744767da57f245b7ca73ddd8036c9..44e7a6d2dfe803a82918c3f29d4ee2cdf9549a02 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java
@@ -103,29 +103,28 @@ public abstract class ExtractVectorNode extends Node {
         return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access.");
     }
 
-    @SuppressWarnings("unused")
     @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"})
-    protected Object accessField(VirtualFrame frame, TruffleObject object, Object[] positions, Object exact, Object dropDimensions,
+    protected Object accessField(TruffleObject object, Object[] positions, @SuppressWarnings("unused") Object exact, @SuppressWarnings("unused") Object dropDimensions,
                     @Cached("createForeignRead(positions)") Node foreignRead,
-                    @Cached("positions.length") int cachedLength,
+                    @Cached("positions.length") @SuppressWarnings("unused") int cachedLength,
                     @Cached("create()") CastStringNode castNode,
                     @Cached("createFirstString()") FirstStringNode firstString,
                     @Cached("createClassProfile()") ValueProfile positionProfile) {
         Object position = positionProfile.profile(positions[0]);
         try {
             if (position instanceof Integer) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((int) position) - 1});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((int) position) - 1});
             } else if (position instanceof Double) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((double) position) - 1});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((double) position) - 1});
             } else if (position instanceof String) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{position});
+                return ForeignAccess.send(foreignRead, object, new Object[]{position});
             } else if (position instanceof RAbstractStringVector) {
                 String string = firstString.executeString(castNode.execute(position));
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{string});
+                return ForeignAccess.send(foreignRead, object, new Object[]{string});
             } else if (position instanceof RAbstractDoubleVector) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((RAbstractDoubleVector) position).getDataAt(0) - 1});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractDoubleVector) position).getDataAt(0) - 1});
             } else if (position instanceof RAbstractIntVector) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((RAbstractIntVector) position).getDataAt(0) - 1});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractIntVector) position).getDataAt(0) - 1});
             } else {
                 throw RError.error(this, RError.Message.GENERIC, "invalid index during foreign access");
             }
@@ -168,7 +167,7 @@ public abstract class ExtractVectorNode extends Node {
         return new CachedExtractVectorNode(node.getMode(), (RTypedValue) vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive);
     }
 
-    @Specialization(contains = "doExtractDefaultCached")
+    @Specialization(replaces = "doExtractDefaultCached")
     @TruffleBoundary
     protected Object doExtractDefaultGeneric(Object vector, Object[] positions, Object exact, Object dropDimensions,  //
                     @Cached("new(createDefaultCache(getThis(), vector, positions, exact, dropDimensions))") GenericVectorExtractNode generic) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCastNode.java
index 78414fda334db4da6b530f787dfa15cfba76eb4b..06410a6a105a41dbe1d641bb9c4922a162873e9d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCastNode.java
@@ -52,7 +52,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
-@SuppressWarnings("unused")
 abstract class PositionCastNode extends Node {
 
     private final ElementAccessMode mode;
@@ -143,7 +142,7 @@ abstract class PositionCastNode extends Node {
     }
 
     @Specialization
-    protected RMissing doMissing(RMissing position) {
+    protected RMissing doMissing(@SuppressWarnings("unused") RMissing position) {
         if (mode.isSubscript()) {
             if (replace) {
                 throw RError.error(this, RError.Message.MISSING_SUBSCRIPT);
@@ -156,12 +155,12 @@ abstract class PositionCastNode extends Node {
     }
 
     @Specialization
-    protected RMissing doEmpty(REmpty position) {
+    protected RMissing doEmpty(@SuppressWarnings("unused") REmpty position) {
         return doMissing(null);
     }
 
     @Specialization
-    protected RAbstractVector doNull(RNull position) {
+    protected RAbstractVector doNull(@SuppressWarnings("unused") RNull position) {
         // NULL expands to integer(0).
         return RDataFactory.createEmptyIntVector();
     }
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 597de75756e45caae79fdefdaa6a4d933ac3f1e1..2514a0825a9618297348320a72c91db76eef80ef 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
@@ -52,9 +52,8 @@ abstract class PositionCheckSubscriptNode extends PositionCheckNode {
         this.recursive = recursive;
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doMissing(PositionProfile statistics, int dimSize, RMissing position, int positionLength) {
+    protected Object doMissing(PositionProfile statistics, int dimSize, RMissing position, @SuppressWarnings("unused") int positionLength) {
         statistics.selectedPositionsCount = dimSize;
         return position;
     }
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 b0ff86b1d0341f2ff8ac13ca26789df5c1f8f51f..e7c74e62eb3dd186919f77d1424cf2e04e41f081 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
@@ -56,9 +56,8 @@ abstract class PositionCheckSubsetNode extends PositionCheckNode {
         super(mode, containerType, positionValue, dimensionIndex, numDimensions, exact, assignment);
     }
 
-    @SuppressWarnings("unused")
     @Specialization
-    protected Object doMissing(PositionProfile statistics, int dimSize, RMissing position, int positionLength) {
+    protected Object doMissing(PositionProfile statistics, int dimSize, RMissing position, @SuppressWarnings("unused") int positionLength) {
         statistics.selectedPositionsCount = dimSize;
         return position;
     }
@@ -92,7 +91,7 @@ abstract class PositionCheckSubsetNode extends PositionCheckNode {
         return b != 0 && (a == b || a % b == 0);
     }
 
-    @Specialization(contains = "doLogicalMultiplesInBounds")
+    @Specialization(replaces = "doLogicalMultiplesInBounds")
     protected RAbstractVector doLogicalGenericInBounds(PositionProfile statistics,  //
                     int dimensionLength, RAbstractLogicalVector position, int positionLength,
                     @Cached("create()") BranchProfile outOfBoundsProfile,
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveExtractSubscriptNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveExtractSubscriptNode.java
index 685ce25e8478d7e79f3dbc64fc72fbce06004720..621139cc8a374fc495e28a0bb029665cefc392c1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveExtractSubscriptNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveExtractSubscriptNode.java
@@ -54,8 +54,8 @@ abstract class RecursiveExtractSubscriptNode extends RecursiveSubscriptNode {
     protected abstract Object execute(VirtualFrame frame, Object vector, Object[] positions, Object firstPosition, int positionLength, Object exact, Object dropDimensions);
 
     @Specialization(guards = "positionLength <= 1")
-    @SuppressWarnings("unused")
-    protected Object doDefault(VirtualFrame frame, Object vector, Object[] positions, Object firstPosition, int positionLength, Object exact, Object dropDimensions) {
+    protected Object doDefault(VirtualFrame frame, Object vector, Object[] positions, @SuppressWarnings("unused") Object firstPosition, @SuppressWarnings("unused") int positionLength, Object exact,
+                    Object dropDimensions) {
         try {
             return subscriptExtract.apply(frame, vector, positions, exact, dropDimensions);
         } catch (RecursiveIndexNotFoundError e) {
@@ -64,9 +64,9 @@ abstract class RecursiveExtractSubscriptNode extends RecursiveSubscriptNode {
         }
     }
 
-    @Specialization(contains = "doDefault")
-    @SuppressWarnings("unused")
-    protected Object doRecursive(VirtualFrame frame, Object vector, Object[] positions, Object originalFirstPosition, int positionLength, Object exact, Object dropDimensions,
+    @Specialization(replaces = "doDefault")
+    protected Object doRecursive(VirtualFrame frame, Object vector, @SuppressWarnings("unused") Object[] positions, Object originalFirstPosition, int positionLength, Object exact,
+                    Object dropDimensions,
                     @Cached("createPositionCast()") PositionCastNode positionCast) {
         Object firstPosition = positionCast.execute(originalFirstPosition);
         Object currentVector = vector;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveReplaceSubscriptNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveReplaceSubscriptNode.java
index 7f6498d58080baaaff29dd21491450aef6bf50e8..f24cc637446d06438573bbd9ad2c2bc09e485c40 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveReplaceSubscriptNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/RecursiveReplaceSubscriptNode.java
@@ -55,8 +55,7 @@ abstract class RecursiveReplaceSubscriptNode extends RecursiveSubscriptNode {
     protected abstract Object execute(VirtualFrame frame, Object vector, Object[] positions, Object firstPosition, int positionLength, Object value);
 
     @Specialization(guards = "positionLength <= 1")
-    @SuppressWarnings("unused")
-    protected Object doDefault(VirtualFrame frame, Object vector, Object[] positions, Object firstPosition, int positionLength, Object value) {
+    protected Object doDefault(VirtualFrame frame, Object vector, Object[] positions, @SuppressWarnings("unused") Object firstPosition, @SuppressWarnings("unused") int positionLength, Object value) {
         return subscriptReplace.apply(frame, vector, positions, value);
     }
 
@@ -71,9 +70,19 @@ abstract class RecursiveReplaceSubscriptNode extends RecursiveSubscriptNode {
      * a[[2]] <- tmp1
      * </code>
      */
-    @Specialization(contains = "doDefault")
-    @SuppressWarnings("unused")
-    protected Object doRecursive(VirtualFrame frame, Object vector, Object[] positions, Object originalFirstPosition, int positionLength, Object value,
+    /**
+     * Exemplary expansion. <code>
+     * a <- list(1,list(1,list(1))); a[[c(2,2,2)]] <- 2
+     * Gets desugared into:
+     * tmp1 <- a[[2]]
+     * tmp2 <- tmp1[[2]]
+     * tmp2[[2]] <- 2
+     * tmp1[[2]] <- tmp2
+     * a[[2]] <- tmp1
+     * </code>
+     */
+    @Specialization(replaces = "doDefault")
+    protected Object doRecursive(VirtualFrame frame, Object vector, @SuppressWarnings("unused") Object[] positions, Object originalFirstPosition, int positionLength, Object value,
                     @Cached("createPositionCast()") PositionCastNode positionCast) {
         Object firstPosition = positionCast.execute(originalFirstPosition);
         Object[] positionStack = new Object[positionLength];
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java
index c8dc9b2cb914658800861960a70ef16d3493e127..03428c908e12d7675b48cfe2fbb093427c9672a2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java
@@ -95,11 +95,10 @@ public abstract class ReplaceVectorNode extends Node {
         return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access.");
     }
 
-    @SuppressWarnings("unused")
     @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"})
-    protected Object accessField(VirtualFrame frame, TruffleObject object, Object[] positions, Object value,
+    protected Object accessField(TruffleObject object, Object[] positions, Object value,
                     @Cached("createForeignWrite(positions)") Node foreignRead,
-                    @Cached("positions.length") int cachedLength,
+                    @SuppressWarnings("unused") @Cached("positions.length") int cachedLength,
                     @Cached("create()") CastStringNode castNode,
                     @Cached("createFirstString()") FirstStringNode firstString) {
 
@@ -112,18 +111,18 @@ public abstract class ReplaceVectorNode extends Node {
         Object position = positions[0];
         try {
             if (position instanceof Integer) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((Integer) position) - 1, writtenValue});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((Integer) position) - 1, writtenValue});
             } else if (position instanceof Double) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((Double) position) - 1, writtenValue});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((Double) position) - 1, writtenValue});
             } else if (position instanceof String) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{position, writtenValue});
+                return ForeignAccess.send(foreignRead, object, new Object[]{position, writtenValue});
             } else if (position instanceof RAbstractStringVector) {
                 String string = firstString.executeString(castNode.execute(position));
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{string, writtenValue});
+                return ForeignAccess.send(foreignRead, object, new Object[]{string, writtenValue});
             } else if (position instanceof RAbstractDoubleVector) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((RAbstractDoubleVector) position).getDataAt(0) - 1, writtenValue});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractDoubleVector) position).getDataAt(0) - 1, writtenValue});
             } else if (position instanceof RAbstractIntVector) {
-                return ForeignAccess.send(foreignRead, frame, object, new Object[]{((RAbstractIntVector) position).getDataAt(0) - 1, writtenValue});
+                return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractIntVector) position).getDataAt(0) - 1, writtenValue});
             } else {
                 throw RError.error(this, RError.Message.GENERIC, "invalid index during foreign access");
             }
@@ -164,7 +163,7 @@ public abstract class ReplaceVectorNode extends Node {
         return mode;
     }
 
-    @Specialization(contains = "doReplaceCached")
+    @Specialization(replaces = "doReplaceCached")
     @TruffleBoundary
     protected Object doReplaceDefaultGeneric(Object vector, Object[] positions, Object value,  //
                     @Cached("new(createDefaultCached(getThis(), vector, positions, value))") GenericVectorReplaceNode generic) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
index ecf96446abf89bb5ae17b87ef1bda2427dd4a4cd..8f9270d9ccd8e45a5b8f76099ba5f391ac604cd8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
@@ -190,10 +190,9 @@ abstract class WriteIndexedVectorNode extends Node {
                     Object[] positions, Object position, int positionOffset, int positionLength,
                     RTypedValue right, Object rightStore, int valueBase, int valueLength, boolean parentNA);
 
-    @SuppressWarnings("unused")
     @Specialization
     protected int doMissing(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension,
-                    Object[] positions, RMissing position, int positionOffset, int positionLength,
+                    Object[] positions, @SuppressWarnings("unused") RMissing position, int positionOffset, @SuppressWarnings("unused") int positionLength,
                     RAbstractContainer right, Object rightStore, int rightBase, int rightLength, boolean parentNA,
                     @Cached("createCountingProfile()") LoopConditionProfile profile) {
         int rightIndex = rightBase;
@@ -286,7 +285,12 @@ abstract class WriteIndexedVectorNode extends Node {
      * positions in an integer vector is significantly lower than the number of elements in the
      * store. This might not be always true and could benefit from more investigation.
      */
-    @Specialization(contains = "doIntegerSequencePosition")
+    /**
+     * Integer vectors iterate over the number of positions because we assume that the number of
+     * positions in an integer vector is significantly lower than the number of elements in the
+     * store. This might not be always true and could benefit from more investigation.
+     */
+    @Specialization(replaces = "doIntegerSequencePosition")
     protected int doIntegerPosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension,
                     Object[] positions, RAbstractIntVector position, int positionOffset, int positionLength,
                     RTypedValue right, Object rightStore, int rightBase, int rightLength, boolean parentNA,
@@ -311,7 +315,6 @@ abstract class WriteIndexedVectorNode extends Node {
         return rightIndex;
     }
 
-    @SuppressWarnings("all")
     private int applyInner(//
                     RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions,
                     Object[] positions, int positionOffset, int positionValue,
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java
index 79e1029c41caf36bc291d62ba3383325411cd3e2..4c07c8bf885e41e3f232114c5217e5cd0f7f6bd4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java
@@ -66,7 +66,7 @@ public abstract class ArrayAttributeNode extends AttributeIterativeAccessNode {
         return result;
     }
 
-    @Specialization(contains = "getArrayFromConstantLayouts")
+    @Specialization(replaces = "getArrayFromConstantLayouts")
     protected RAttribute[] getArrayFallback(DynamicObject attrs) {
         Shape shape = attrs.getShape();
         List<Property> props = shape.getPropertyList();
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 05d4cf11a6e67f1c7f78397b8072c9184fd52655..7118f008d8b60b50368ebf25865099e9680f6e10 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
@@ -58,9 +58,8 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
         return CopyOfRegAttributesNodeGen.create();
     }
 
-    @SuppressWarnings("unused")
     @Specialization(guards = "source.getAttributes() == null")
-    protected void copyNoAttributes(RAbstractVector source, RVector<?> target) {
+    protected void copyNoAttributes(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) {
         // nothing to do
     }
 
@@ -69,9 +68,8 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
         return attributes == null || attributes.isEmpty();
     }
 
-    @SuppressWarnings("unused")
-    @Specialization(guards = "emptyAttributes(source)", contains = "copyNoAttributes")
-    protected void copyEmptyAttributes(RAbstractVector source, RVector<?> target) {
+    @Specialization(guards = "emptyAttributes(source)", replaces = "copyNoAttributes")
+    protected void copyEmptyAttributes(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) {
         // nothing to do
     }
 
@@ -80,9 +78,8 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
         return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && dimAttrGetter.execute(attributes) != null;
     }
 
-    @SuppressWarnings("unused")
     @Specialization(guards = "onlyDimAttribute(source)")
-    protected void copyDimOnly(RAbstractVector source, RVector<?> target) {
+    protected void copyDimOnly(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) {
         // nothing to do
     }
 
@@ -91,9 +88,8 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
         return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && namesAttrGetter.execute(attributes) != null;
     }
 
-    @SuppressWarnings("unused")
     @Specialization(guards = "onlyNamesAttribute(source)")
-    protected void copyNamesOnly(RAbstractVector source, RVector<?> target) {
+    protected void copyNamesOnly(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) {
         // nothing to do
     }
 
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 00cbacb9d148fba16704a411e4b779ec8e965352..dd749a55ff746724379af75f39ad64ee540aa527 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
@@ -65,7 +65,7 @@ public abstract class GetAttributeNode extends AttributeAccessNode {
     }
 
     @TruffleBoundary
-    @Specialization(contains = {"getAttrCached"})
+    @Specialization(replaces = {"getAttrCached"})
     protected Object getAttrFallback(DynamicObject attrs, String name) {
         return attrs.get(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 e003117e424bf6b61013db3770d28b5396b9286c..ede99fc59e6c04242140dfac4cb00b91f2b4d203 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
@@ -87,7 +87,7 @@ public abstract class GetFixedAttributeNode extends FixedAttributeAccessNode {
         return location == null ? null : location.get(attrs, shape);
     }
 
-    @Specialization(contains = "getAttrCached")
+    @Specialization(replaces = "getAttrCached")
     @TruffleBoundary
     protected Object getAttrFallback(DynamicObject attrs) {
         return attrs.get(name);
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
index ec1a84268eac98fc227bd131fdeeccf9d340e78a..24f02dcac6b1ed3568df47b8fefbbad712464425 100644
--- 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
@@ -67,14 +67,13 @@ public abstract class HasFixedAttributeNode extends FixedAttributeAccessNode {
     @Specialization(limit = "3", //
                     guards = {"shapeCheck(shape, attrs)"}, //
                     assumptions = {"shape.getValidAssumption()"})
-    @SuppressWarnings("unused")
-    protected boolean hasAttrCached(DynamicObject attrs,
-                    @Cached("lookupShape(attrs)") Shape shape,
+    protected boolean hasAttrCached(@SuppressWarnings("unused") DynamicObject attrs,
+                    @Cached("lookupShape(attrs)") @SuppressWarnings("unused") Shape shape,
                     @Cached("lookupLocation(shape, name)") Location location) {
         return location != null;
     }
 
-    @Specialization(contains = "hasAttrCached")
+    @Specialization(replaces = "hasAttrCached")
     @TruffleBoundary
     protected boolean hasAttrFallback(DynamicObject attrs) {
         return attrs.containsKey(name);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java
index 9032aaefedfbd5b61744a27671cf38dc243df9f7..3071f904c04189f5ae5a68c6a4bc1a966824979b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,7 @@ public abstract class IterableAttributeNode extends AttributeIterativeAccessNode
         return RAttributesLayout.asIterable(attrs, attrsLayout);
     }
 
-    @Specialization(contains = "getArrayFromConstantLayouts")
+    @Specialization(replaces = "getArrayFromConstantLayouts")
     @TruffleBoundary
     protected RAttributesLayout.RAttributeIterable getArrayFallback(DynamicObject attrs) {
         return RAttributesLayout.asIterable(attrs);
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 812da601b1a5581809264d37ed878d6a60ac49d1..dd75f36d56315792716213f518e170a0cddd916b 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -72,9 +72,8 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
                     assumptions = {
                                     "shape.getValidAssumption()"
                     })
-    @SuppressWarnings("unused")
-    protected static void setExistingAttrCached(DynamicObject attrs, String name, Object value,
-                    @Cached("name") String cachedName,
+    protected static void setExistingAttrCached(DynamicObject attrs, @SuppressWarnings("unused") String name, Object value,
+                    @Cached("name") @SuppressWarnings("unused") String cachedName,
                     @Cached("lookupShape(attrs)") Shape shape,
                     @Cached("lookupLocation(shape, name, value)") Location location) {
         try {
@@ -114,7 +113,7 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
      * polymorphic inline cache.
      */
     @TruffleBoundary
-    @Specialization(contains = {"setExistingAttrCached", "setNewAttrCached"})
+    @Specialization(replaces = {"setExistingAttrCached", "setNewAttrCached"})
     protected static void setAttrFallback(DynamicObject receiver, String name, Object value) {
         receiver.define(name, value);
     }
@@ -136,7 +135,7 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
         setSpecAttrNode.execute(x, value);
     }
 
-    @Specialization(contains = "setSpecAttrInAttributable", //
+    @Specialization(replaces = "setSpecAttrInAttributable", //
                     guards = "isSpecialAttributeNode.execute(name)")
     @SuppressWarnings("unused")
     protected void setSpecAttrInAttributable(RAttributable x, String name, Object value,
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 8a8459086e495ab6bd45bd3def4026b343952725..0f46af182b3804468f8ca68e4d273568911a2fb8 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
@@ -117,7 +117,7 @@ public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
         return oldShape.defineProperty(name, value, 0);
     }
 
-    @Specialization(contains = "setAttrCached")
+    @Specialization(replaces = "setAttrCached")
     @TruffleBoundary
     protected void setFallback(DynamicObject attrs, Object value) {
         attrs.define(name, value);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/TypeFromModeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/TypeFromModeNode.java
index f44b724a1de132f9d5fa001283a452ed6e831f30..6e4fbbc901d66dd099ad35ce3496643f2ddde4a3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/TypeFromModeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/TypeFromModeNode.java
@@ -40,10 +40,9 @@ public abstract class TypeFromModeNode extends Node {
 
     public abstract RType execute(Object mode);
 
-    @SuppressWarnings("unused")
     @Specialization(limit = "CACHE_LIMIT", guards = "mode == cachedMode")
-    protected RType getTypeCAched(String mode,
-                    @Cached("mode") String cachedMode,
+    protected RType getTypeCAched(@SuppressWarnings("unused") String mode,
+                    @Cached("mode") @SuppressWarnings("unused") String cachedMode,
                     @Cached("fromMode(mode)") RType type) {
         return type;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
index 09a759cdf26d432d49ca4849febc804bb271127c..cbf0003eecd8b8e5b9efc923888ecbf2d9be2c6a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java
@@ -29,7 +29,6 @@ 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.ValueProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.primitive.BinaryMapNode;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
@@ -67,8 +66,8 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         this.unary = unaryFactory;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(BinaryArithmeticNode.class);
         casts.arg(0).boxPrimitive();
         casts.arg(1).boxPrimitive();
     }
@@ -83,7 +82,7 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode {
         return cached.apply(left, right);
     }
 
-    @Specialization(contains = "doNumericVectorCached", guards = {"isNumericVector(left)", "isNumericVector(right)"})
+    @Specialization(replaces = "doNumericVectorCached", guards = {"isNumericVector(left)", "isNumericVector(right)"})
     @TruffleBoundary
     protected Object doNumericVectorGeneric(Object left, Object right,
                     @Cached("binary.createOperation()") BinaryArithmetic arithmetic,
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
index 2464725d5b8e47e3c3b9bb2baecbcf50204d6451..1101328086708d74d6745c6aa393474f5d8bd352 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java
@@ -28,7 +28,6 @@ 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.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.primitive.BinaryMapNode;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
@@ -67,8 +66,8 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         this.factory = factory;
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(BinaryBooleanNode.class);
         casts.arg(0).boxPrimitive();
         casts.arg(1).boxPrimitive();
     }
@@ -93,7 +92,7 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return cached.apply(left, right);
     }
 
-    @Specialization(contains = "doNumericVectorCached", guards = "isSupported(left, right)")
+    @Specialization(replaces = "doNumericVectorCached", guards = "isSupported(left, right)")
     @TruffleBoundary
     protected Object doNumericVectorGeneric(Object left, Object right,
                     @Cached("factory.createOperation()") BooleanOperation operation,
@@ -134,15 +133,19 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
                     @Cached("createRecursive()") BinaryBooleanNode recursive) {
         Object recursiveLeft = left;
         if (isSymbolOrLang(left)) {
-            recursiveLeft = RString.valueOf(RDeparse.deparse(left));
+            recursiveLeft = deparseSymbolOrLang(left);
         }
         Object recursiveRight = right;
         if (isSymbolOrLang(right)) {
-            recursiveRight = RString.valueOf(RDeparse.deparse(right));
+            recursiveRight = deparseSymbolOrLang(right);
         }
         return recursive.execute(frame, recursiveLeft, recursiveRight);
     }
 
+    private static RString deparseSymbolOrLang(Object val) {
+        return RString.valueOf(RDeparse.deparse(val, RDeparse.MAX_Cutoff, false, RDeparse.KEEPINTEGER, -1));
+    }
+
     protected BinaryBooleanNode createRecursive() {
         return BinaryBooleanNode.create(factory);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
index 67e8a9132030280ceffc39722e3008f647e11003..3026310ff21bd27440abc320c7cb1fd058d55a31 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
@@ -62,6 +62,10 @@ public abstract class BinaryBooleanScalarNode extends RBuiltinNode {
 
     private final BooleanOperation booleanLogic;
 
+    static {
+        Casts.noCasts(BinaryBooleanScalarNode.class);
+    }
+
     BinaryBooleanScalarNode(BooleanOperationFactory factory) {
         this.booleanLogic = factory.createOperation();
         logic = new BinaryMapBooleanFunctionNode(booleanLogic);
@@ -105,7 +109,7 @@ public abstract class BinaryBooleanScalarNode extends RBuiltinNode {
             return castImpl(cachedClass.cast(operand));
         }
 
-        @Specialization(contains = "doCached", guards = {"operand.getRType().isNumeric()"})
+        @Specialization(replaces = "doCached", guards = {"operand.getRType().isNumeric()"})
         @TruffleBoundary
         protected byte doGeneric(RAbstractVector operand) {
             return castImpl(operand);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java
index 11825aaf02cece30f2205fb0ea953ac6e8b5fc73..36f9c1ca7505be6d75c2ac06bde56adb190c2d46 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,10 +23,10 @@
 package com.oracle.truffle.r.nodes.binary;
 
 import com.oracle.truffle.api.dsl.NodeChild;
-import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
-@NodeChildren({@NodeChild(value = "left", type = RNode.class), @NodeChild(value = "right", type = RNode.class)})
+@NodeChild(value = "left", type = RNode.class)
+@NodeChild(value = "right", type = RNode.class)
 abstract class BinaryNode extends RNode {
 
     protected abstract RNode getLeft();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BoxPrimitiveNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BoxPrimitiveNode.java
index a6b5c6125d15311ba25f79321d50853db541580d..192e48d595c2400a4985a13466b9d210bf4085a1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BoxPrimitiveNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BoxPrimitiveNode.java
@@ -74,7 +74,7 @@ public abstract class BoxPrimitiveNode extends CastNode {
         return cachedClass.cast(vector);
     }
 
-    @Specialization(contains = "doCached", guards = "!isPrimitive(vector)")
+    @Specialization(replaces = "doCached", guards = "!isPrimitive(vector)")
     protected static Object doGeneric(Object vector) {
         return vector;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java
index 663081d1a9d6303b10f3cf3528ae04b665d103e1..98aedf151d9e5d4d1441b6b3313700816ca26755 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java
@@ -51,12 +51,10 @@ import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FilterStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapIfStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.NotNAStep;
-import com.oracle.truffle.r.nodes.builtin.casts.PipelineToCastNode;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.ChainBuilder;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.FindFirstNodeBuilder;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.InitialPhaseBuilder;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.PipelineBuilder;
-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.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -93,7 +91,6 @@ public final class CastBuilder {
     private final RBuiltin builtin;
     private final String[] argumentNames;
     private PipelineBuilder[] argumentBuilders;
-    private CastNode[] castsCache = null;
 
     public CastBuilder(RBuiltin builtin) {
         // Note: if we have the builtin metadata, we pre-allocate the arrays, builtinNode != null is
@@ -127,16 +124,14 @@ public final class CastBuilder {
      * casting, returns {@code null} as its cast node.
      */
     public CastNode[] getCasts() {
-        if (castsCache == null) {
-            castsCache = new CastNode[argumentBuilders.length];
-            for (int i = 0; i < argumentBuilders.length; i++) {
-                PipelineBuilder arg = argumentBuilders[i];
-                if (arg != null) {
-                    castsCache[i] = PipelineToCastNode.convert(arg.getPipelineConfig().build(), arg.getFirstStep());
-                }
+        CastNode[] castNodes = new CastNode[argumentBuilders.length];
+        for (int i = 0; i < argumentBuilders.length; i++) {
+            PipelineBuilder arg = argumentBuilders[i];
+            if (arg != null) {
+                castNodes[i] = arg.buildNode();
             }
         }
-        return castsCache;
+        return castNodes;
     }
 
     // ---------------------
@@ -218,27 +213,27 @@ public final class CastBuilder {
      *
      * Analogous methods exist for {@code RMissing}.
      */
-    public PreinitialPhaseBuilder<Object> arg(String argumentName) {
+    public PreinitialPhaseBuilder arg(String argumentName) {
         assert builtin != null : "arg(String) is only supported for builtins cast pipelines";
-        return new PreinitialPhaseBuilder<>(getBuilder(getArgumentIndex(argumentName), argumentName));
+        return getBuilder(getArgumentIndex(argumentName), argumentName).fluent();
     }
 
     /**
      * @see #arg(String)
      */
-    public PreinitialPhaseBuilder<Object> arg(int argumentIndex, String argumentName) {
+    public PreinitialPhaseBuilder arg(int argumentIndex, String argumentName) {
         assert argumentNames == null || argumentIndex >= 0 && argumentIndex < argumentBuilders.length : "argument index out of range";
         assert argumentNames == null || argumentNames[argumentIndex].equals(argumentName) : "wrong argument name " + argumentName;
-        return new PreinitialPhaseBuilder<>(getBuilder(argumentIndex, argumentName));
+        return getBuilder(argumentIndex, argumentName).fluent();
     }
 
     /**
      * @see #arg(String)
      */
-    public PreinitialPhaseBuilder<Object> arg(int argumentIndex) {
+    public PreinitialPhaseBuilder arg(int argumentIndex) {
         boolean existingIndex = argumentNames != null && argumentIndex >= 0 && argumentIndex < argumentNames.length;
         String name = existingIndex ? argumentNames[argumentIndex] : null;
-        return new PreinitialPhaseBuilder<>(getBuilder(argumentIndex, name));
+        return getBuilder(argumentIndex, name).fluent();
     }
 
     private PipelineBuilder getBuilder(int argumentIndex, String argumentName) {
@@ -248,7 +243,7 @@ public final class CastBuilder {
             argumentBuilders = Arrays.copyOf(argumentBuilders, argumentIndex + 1);
         }
         if (argumentBuilders[argumentIndex] == null) {
-            argumentBuilders[argumentIndex] = new PipelineBuilder(new PipelineConfigBuilder(argumentName));
+            argumentBuilders[argumentIndex] = new PipelineBuilder(argumentName);
         }
         return argumentBuilders[argumentIndex];
     }
@@ -303,13 +298,21 @@ public final class CastBuilder {
         }
 
         public static <T, S extends T, R> PipelineStep<T, R> mapIf(Filter<? super T, S> filter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch) {
-            return new MapIfStep<>(filter, trueBranch, falseBranch);
+            return new MapIfStep<>(filter, trueBranch, falseBranch, false);
+        }
+
+        public static <T, S extends T, R> PipelineStep<T, R> returnIf(Filter<? super T, S> filter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch) {
+            return new MapIfStep<>(filter, trueBranch, falseBranch, true);
         }
 
         public static <T, S extends T, R> PipelineStep<T, R> mapIf(Filter<? super T, S> filter, PipelineStep<?, ?> trueBranch) {
             return mapIf(filter, trueBranch, null);
         }
 
+        public static <T, S extends T, R> PipelineStep<T, R> returnIf(Filter<? super T, S> filter, PipelineStep<?, ?> trueBranch) {
+            return returnIf(filter, trueBranch, null);
+        }
+
         public static <T> ChainBuilder<T> chain(PipelineStep<T, ?> firstStep) {
             return new ChainBuilder<>(firstStep);
         }
@@ -318,26 +321,50 @@ public final class CastBuilder {
             return new CoercionStep<>(RType.Integer, false);
         }
 
+        public static <T> PipelineStep<T, Integer> asInteger(RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Integer, false, false, false, false, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, RAbstractIntVector> asIntegerVector() {
             return new CoercionStep<>(RType.Integer, true);
         }
 
+        public static <T> PipelineStep<T, RAbstractIntVector> asIntegerVector(RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Integer, true, false, false, false, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, RAbstractIntVector> asIntegerVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-            return new CoercionStep<>(RType.Integer, true, preserveNames, preserveDimensions, preserveAttributes);
+            return new CoercionStep<>(RType.Integer, true, preserveNames, preserveDimensions, preserveAttributes, true, null);
+        }
+
+        public static <T> PipelineStep<T, RAbstractIntVector> asIntegerVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Integer, true, preserveNames, preserveDimensions, preserveAttributes, true, messageCallerObj);
         }
 
         public static <T> PipelineStep<T, Double> asDouble() {
             return new CoercionStep<>(RType.Double, false);
         }
 
+        public static <T> PipelineStep<T, Double> asDouble(RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Double, false, false, false, false, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, RAbstractDoubleVector> asDoubleVector() {
             return new CoercionStep<>(RType.Double, true);
         }
 
+        public static <T> PipelineStep<T, RAbstractDoubleVector> asDoubleVector(RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Double, true, false, false, false, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, RAbstractDoubleVector> asDoubleVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
             return new CoercionStep<>(RType.Double, true, preserveNames, preserveDimensions, preserveAttributes);
         }
 
+        public static <T> PipelineStep<T, RAbstractDoubleVector> asDoubleVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Double, true, preserveNames, preserveDimensions, preserveAttributes, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, String> asString() {
             return new CoercionStep<>(RType.Character, false);
         }
@@ -354,6 +381,10 @@ public final class CastBuilder {
             return new CoercionStep<>(RType.Complex, true);
         }
 
+        public static <T> PipelineStep<T, RAbstractComplexVector> asComplex(RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Complex, false, false, false, false, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, RAbstractRawVector> asRawVector() {
             return new CoercionStep<>(RType.Raw, true);
         }
@@ -362,12 +393,24 @@ public final class CastBuilder {
             return new CoercionStep<>(RType.Logical, false);
         }
 
+        public static <T> PipelineStep<T, Byte> asLogical(RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Logical, false, false, false, false, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, RAbstractLogicalVector> asLogicalVector() {
             return new CoercionStep<>(RType.Logical, true);
         }
 
+        public static <T> PipelineStep<T, RAbstractLogicalVector> asLogicalVector(RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Logical, true, false, false, false, true, messageCallerObj);
+        }
+
         public static <T> PipelineStep<T, RAbstractLogicalVector> asLogicalVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-            return new CoercionStep<>(RType.Logical, true, preserveNames, preserveDimensions, preserveAttributes, false);
+            return new CoercionStep<>(RType.Logical, true, preserveNames, preserveDimensions, preserveAttributes, false, null);
+        }
+
+        public static <T> PipelineStep<T, RAbstractLogicalVector> asLogicalVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+            return new CoercionStep<>(RType.Logical, true, preserveNames, preserveDimensions, preserveAttributes, true, messageCallerObj);
         }
 
         public static PipelineStep<Byte, Boolean> asBoolean() {
@@ -379,7 +422,7 @@ public final class CastBuilder {
         }
 
         public static <T> PipelineStep<T, RAbstractVector> asVector(boolean preserveNonVector) {
-            return new CoercionStep<>(RType.Any, true, false, false, false, preserveNonVector);
+            return new CoercionStep<>(RType.Any, true, false, false, false, preserveNonVector, null);
         }
 
         /**
@@ -647,11 +690,11 @@ public final class CastBuilder {
         }
 
         public static <R> TypeFilter<Object, R> instanceOf(Class<R> cls) {
-            return new TypeFilter<>(x -> cls.isInstance(x), cls);
+            return new TypeFilter<>(cls);
         }
 
         public static TypeFilter<Object, RFunction> builtin() {
-            return new TypeFilter<>(x -> RFunction.class.isInstance(x) && ((RFunction) x).isBuiltin(), RFunction.class);
+            return new TypeFilter<>(RFunction.class, x -> x.isBuiltin());
         }
 
         public static <R extends RAbstractIntVector> Filter<Object, R> integerValue() {
@@ -678,8 +721,8 @@ public final class CastBuilder {
             return new RTypeFilter<>(RType.Raw);
         }
 
-        public static <R> TypeFilter<Object, R> anyValue() {
-            return new TypeFilter<>(x -> true, Object.class);
+        public static TypeFilter<Object, Object> anyValue() {
+            return new TypeFilter<>(Object.class);
         }
 
         @SuppressWarnings({"rawtypes", "unchecked"})
@@ -699,11 +742,11 @@ public final class CastBuilder {
         }
 
         public static Filter<Object, Integer> atomicIntegerValue() {
-            return new TypeFilter<>(x -> x instanceof String, String.class);
+            return new TypeFilter<>(Integer.class);
         }
 
         public static Filter<Object, Byte> atomicLogicalValue() {
-            return new TypeFilter<>(x -> x instanceof Byte, Byte.class);
+            return new TypeFilter<>(Byte.class);
         }
 
         public static MapByteToBoolean toBoolean() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/NodeWithArgumentCasts.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/NodeWithArgumentCasts.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd1b4a44df02358d9f906a802376a1a563e9abb9
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/NodeWithArgumentCasts.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.oracle.truffle.api.dsl.GeneratedBy;
+import com.oracle.truffle.r.nodes.builtin.casts.fluent.PreinitialPhaseBuilder;
+import com.oracle.truffle.r.nodes.unary.CastNode;
+import com.oracle.truffle.r.nodes.unary.UnaryArithmeticBuiltinNode;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+
+public interface NodeWithArgumentCasts {
+
+    default Casts getCastHolder() {
+        Class<?> cls = Casts.getBuiltinClass(getClass());
+        Casts casts = Casts.forClass(cls);
+        assert casts != null || Casts.noCastsAllowed(getClass().getSuperclass()) : "No casts associated with builtin " + cls;
+        return casts == null ? Casts.empty : casts;
+    }
+
+    default CastNode[] getCasts() {
+        CastNode[] casts = getCastHolder().getCastNodes();
+        return casts;
+    }
+
+    final class Casts {
+        private static final ConcurrentHashMap<Class<?>, Casts> castsMap = new ConcurrentHashMap<>();
+        private static final Casts empty = new Casts();
+
+        protected final CastBuilder casts;
+
+        private Casts() {
+            casts = new CastBuilder();
+        }
+
+        public Casts(Class<? extends NodeWithArgumentCasts> cls) {
+            casts = new CastBuilder(cls.getAnnotation(RBuiltin.class));
+            castsMap.put(cls, this);
+        }
+
+        public static void noCasts(Class<? extends NodeWithArgumentCasts> cls) {
+            castsMap.put(cls, new Casts(cls));
+        }
+
+        public static Casts forClass(Class<?> cls) {
+            return castsMap.get(cls);
+        }
+
+        public CastNode[] getCastNodes() {
+            return casts.getCasts();
+        }
+
+        public PreinitialPhaseBuilder arg(String argumentName) {
+            return casts.arg(argumentName);
+        }
+
+        public PreinitialPhaseBuilder arg(int argumentIndex, String argumentName) {
+            return casts.arg(argumentIndex, argumentName);
+        }
+
+        public PreinitialPhaseBuilder arg(int argumentIndex) {
+            return casts.arg(argumentIndex);
+        }
+
+        private static boolean noCastsAllowed(Class<?> cls) {
+            boolean res = RExternalBuiltinNode.Arg0.class.isAssignableFrom(cls) || UnaryArithmeticBuiltinNode.class.isAssignableFrom(cls) ||
+                            (RBuiltinNode.class.isAssignableFrom(cls) && hasNoArguments(cls));
+            return res;
+        }
+
+        private static boolean hasNoArguments(Class<?> cls) {
+            RBuiltin a = cls.getAnnotation(RBuiltin.class);
+            return a != null && a.parameterNames().length == 0;
+        }
+
+        private static Class<?> getBuiltinClass(Class<?> cls) {
+            if (cls.getAnnotation(GeneratedBy.class) != null) {
+                return cls.getSuperclass();
+            } else {
+                return cls;
+            }
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
index 4449df431ef06c6e7f42bec23d7d94648877b661..579352ce12d9b2c9b7eff4fa13c13335e7d81dfc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinNode.java
@@ -32,7 +32,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.RCallNode;
-import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
@@ -47,20 +46,10 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 
 @TypeSystemReference(RTypes.class)
-public abstract class RBuiltinNode extends RBaseNode {
+public abstract class RBuiltinNode extends RBaseNode implements NodeWithArgumentCasts {
 
     public abstract Object executeBuiltin(VirtualFrame frame, Object... args);
 
-    protected void createCasts(@SuppressWarnings("unused") CastBuilder casts) {
-        // nothing to do
-    }
-
-    public CastNode[] getCasts() {
-        CastBuilder builder = new CastBuilder(getRBuiltin());
-        createCasts(builder);
-        return builder.getCasts();
-    }
-
     /**
      * Return the default values of the builtin's formal arguments. This is only valid for builtins
      * of {@link RBuiltinKind kind} PRIMITIVE or SUBSTITUTE. Only simple scalar constants and
@@ -132,4 +121,5 @@ public abstract class RBuiltinNode extends RBaseNode {
     public String toString() {
         return (getRBuiltin() == null ? getClass().getSimpleName() : getRBuiltin().name());
     }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java
index 9e0044e2416661076963972c25b27bc29069cfbd..88652dcff593da9f9dbe5f59bcddc6c084d16c8c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -89,7 +89,7 @@ public final class RBuiltinRootNode extends RRootNode {
             throw new RInternalError(e, "internal error");
         } finally {
             visibility.execute(frame, factory.getVisibility());
-            visibility.executeEndOfFunction(frame, this);
+            visibility.executeEndOfFunction(frame);
         }
     }
 
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 60c5f72e5830f273253b0b708b2c0b9b9961d67f..8f4ad0a026fe1d885d3399bd7bb9f9a425cab5de 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
@@ -48,7 +48,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @TypeSystemReference(RTypes.class)
-public abstract class RExternalBuiltinNode extends RBaseNode {
+public abstract class RExternalBuiltinNode extends RBaseNode implements NodeWithArgumentCasts {
 
     public Object call(@SuppressWarnings("unused") VirtualFrame frame, RArgsValuesAndNames args) {
         return call(args);
@@ -56,16 +56,6 @@ public abstract class RExternalBuiltinNode extends RBaseNode {
 
     protected abstract Object call(RArgsValuesAndNames args);
 
-    protected void createCasts(@SuppressWarnings("unused") CastBuilder casts) {
-        // nothing to do
-    }
-
-    public CastNode[] getCasts() {
-        CastBuilder builder = new CastBuilder();
-        createCasts(builder);
-        return builder.getCasts();
-    }
-
     // TODO: these should be in the build nodes
     @Child private CastLogicalNode castLogical;
     @Child private CastIntegerNode castInt;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
index 78914ee9313f30da5b6375abe5aac790555c4695..05e91851108907a73d5716dc0e76df049bb96fa4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInternalCodeBuiltinNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,10 @@ public final class RInternalCodeBuiltinNode extends RExternalBuiltinNode {
     @Child private CallMatcherNode call = CallMatcherNode.create(true);
     @CompilationFinal private RFunction function;
 
+    static {
+        Casts.noCasts(RInternalCodeBuiltinNode.class);
+    }
+
     public RInternalCodeBuiltinNode(RContext context, String basePackage, Source code, String functionName) {
         this.context = context;
         this.basePackage = basePackage;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java
index a50458a51a216058dcab72e3f6c6ef9989e731b0..cc2264b97ca612c1b46b448bac53deb1b6c53991 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java
@@ -33,6 +33,15 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * Abstracted for use by other nodes that need to convert a list into an environment.
  */
 public final class RList2EnvNode extends RBaseNode {
+    private final boolean ignoreMissingNames;
+
+    public RList2EnvNode() {
+        this(false);
+    }
+
+    public RList2EnvNode(boolean ignoreMissingNames) {
+        this.ignoreMissingNames = ignoreMissingNames;
+    }
 
     @TruffleBoundary
     public REnvironment execute(RAbstractListVector list, REnvironment env) {
@@ -45,7 +54,7 @@ public final class RList2EnvNode extends RBaseNode {
         }
         for (int i = list.getLength() - 1; i >= 0; i--) {
             String name = names.getDataAt(i);
-            if (name.length() == 0) {
+            if (!ignoreMissingNames && name.length() == 0) {
                 throw RError.error(this, RError.Message.ZERO_LENGTH_VARIABLE);
             }
             // in case of duplicates, last element in list wins
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java
index c74b22baa8d1bf3165b532933635b9c242071b81..f26904e04cb65c7a0a377940a3408b9a58bdc94b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.builtin.casts;
 
+import java.util.function.Predicate;
+
 import com.oracle.truffle.r.nodes.builtin.ArgumentFilter;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FilterStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
@@ -91,16 +93,45 @@ public abstract class Filter<T, R extends T> {
      * Filters specific Java class.
      */
     public static final class TypeFilter<T, R extends T> extends Filter<T, R> {
-        private final Class<?>[] type;
-        private final ArgumentFilter<Object, Object> instanceOfLambda;
+        private final Class<?> type1;
+        private final Class<?> type2;
+        private final Predicate<R> extraCondition;
 
-        public TypeFilter(ArgumentFilter<Object, Object> instanceOfLambda, Class<?>... type) {
-            this.type = type;
-            this.instanceOfLambda = instanceOfLambda;
+        @SuppressWarnings("rawtypes")
+        public TypeFilter(Class<R> type) {
+            assert type != null;
+            this.type1 = type;
+            this.type2 = null;
+            this.extraCondition = null;
         }
 
-        public Class<?>[] getType() {
-            return type;
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public TypeFilter(Class<R> type, Predicate<R> extraCondition) {
+            assert type != null;
+            this.type1 = type;
+            this.type2 = null;
+            this.extraCondition = extraCondition;
+        }
+
+        @SuppressWarnings("rawtypes")
+        public TypeFilter(Class<?> type1, Class<?> type2) {
+            assert type1 != null && type2 != null;
+            assert type1 != Object.class && type2 != Object.class;
+            this.type1 = type1;
+            this.type2 = type2;
+            this.extraCondition = null;
+        }
+
+        public Class<?> getType1() {
+            return type1;
+        }
+
+        public Class<?> getType2() {
+            return type2;
+        }
+
+        public Predicate<R> getExtraCondition() {
+            return extraCondition;
         }
 
         @Override
@@ -108,7 +139,26 @@ public abstract class Filter<T, R extends T> {
             return true;
         }
 
+        @SuppressWarnings("unchecked")
         public ArgumentFilter<Object, Object> getInstanceOfLambda() {
+            final ArgumentFilter<Object, Object> instanceOfLambda;
+            if (type2 == null) {
+                if (extraCondition == null) {
+                    if (type1 == Object.class) {
+                        instanceOfLambda = x -> true;
+                    } else {
+                        instanceOfLambda = x -> type1.isInstance(x);
+                    }
+                } else {
+                    if (type1 == Object.class) {
+                        instanceOfLambda = x -> extraCondition.test((R) x);
+                    } else {
+                        instanceOfLambda = x -> type1.isInstance(x) && extraCondition.test((R) x);
+                    }
+                }
+            } else {
+                instanceOfLambda = x -> type1.isInstance(x) || type2.isInstance(x);
+            }
             return instanceOfLambda;
         }
 
@@ -126,6 +176,7 @@ public abstract class Filter<T, R extends T> {
         public ResultForArg resultForMissing() {
             return ResultForArg.FALSE;
         }
+
     }
 
     /**
@@ -363,6 +414,16 @@ public abstract class Filter<T, R extends T> {
         public <D> D accept(FilterVisitor<D> visitor) {
             return visitor.visit(this);
         }
+
+        @Override
+        public ResultForArg resultForNull() {
+            if (subject instanceof VectorSize && ((VectorSize) subject).size == 0) {
+                return ResultForArg.TRUE;
+            } else {
+                return ResultForArg.FALSE;
+            }
+        }
+
     }
 
     public abstract static class MatrixFilter<T extends RAbstractVector> extends Filter<T, T> {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java
index 3ecb60adfca4cf4eb01255ed452e965b90bec7d4..42146741e4b0416856857914b0f68e07e57005be 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,14 +48,17 @@ public class PipelineConfig {
     private final Mapper<? super RNull, ?> nullMapper;
     private final MessageData missingMsg;
     private final MessageData nullMsg;
+    private boolean valueForwarding;
 
     public PipelineConfig(String argumentName, MessageData defaultError, MessageData defaultWarning, Mapper<? super RMissing, ?> missingMapper, Mapper<? super RNull, ?> nullMapper,
+                    boolean valueForwarding,
                     MessageData missingMsg,
                     MessageData nullMsg) {
         this.defaultError = defaultError;
         this.defaultWarning = defaultWarning;
         this.missingMapper = missingMapper;
         this.nullMapper = nullMapper;
+        this.valueForwarding = valueForwarding;
         this.missingMsg = missingMsg;
         this.nullMsg = nullMsg;
         this.argumentName = argumentName;
@@ -93,6 +96,10 @@ public class PipelineConfig {
         return nullMsg;
     }
 
+    public boolean getValueForwarding() {
+        return valueForwarding;
+    }
+
     public static ArgumentFilterFactory getFilterFactory() {
         return filterFactory;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java
index a253a907b280a9608138be1440860a102ed882ff..e6bbe5e5a4dd973d1f44c9005321aa054bad2640 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineStep.java
@@ -25,11 +25,12 @@ package com.oracle.truffle.r.nodes.builtin.casts;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * Represents a single step in the cast pipeline. {@code PipelineStep}, {@code Mapper} and
  * {@code Filter} are only symbolic representation of the pipeline, these objects can be transformed
- * to something useful by using corresponding visitors, e.g. {@linek PipelineStepVisitor}. Steps can
+ * to something useful by using corresponding visitors, e.g. {@link PipelineStepVisitor}. Steps can
  * be chained as a linked list by setting the next step in the chain using
  * {@link #setNext(PipelineStep)}. The order of steps should be the same as the order of cast
  * pipeline API invocations.
@@ -49,6 +50,16 @@ public abstract class PipelineStep<T, R> {
 
     public abstract <D> D accept(PipelineStepVisitor<D> visitor);
 
+    public <D> D acceptPipeline(PipelineStepVisitor<D> visitor) {
+        PipelineStep<?, ?> curStep = this;
+        D result = null;
+        while (curStep != null) {
+            result = curStep.accept(visitor);
+            curStep = curStep.getNext();
+        }
+        return result;
+    }
+
     public interface PipelineStepVisitor<T> {
         T visit(FindFirstStep<?, ?> step);
 
@@ -187,14 +198,16 @@ public abstract class PipelineStep<T, R> {
     }
 
     /**
-     * Converts the value to a vector of given type (or a vector if Any, or Attributable). Null and
-     * missing values are forwarded.
+     * Converts the value to a vector of given type (or a vector if Any, or Attributable). Null,
+     * missing and primitive of given type are forwarded. Primitive values of other types are
+     * converted to primitive value of the target type.
      */
     public static final class CoercionStep<T, V> extends PipelineStep<T, V> {
         public final RType type;
         public final boolean preserveNames;
         public final boolean preserveDimensions;
         public final boolean preserveAttributes;
+        public final RBaseNode messageCallObj;
 
         /**
          * Whether RNull/RMissing should be preserved, or converted to an empty list.
@@ -207,26 +220,31 @@ public abstract class PipelineStep<T, R> {
         public final boolean vectorCoercion;
 
         public CoercionStep(RType type, boolean vectorCoercion) {
-            this(type, vectorCoercion, false, false, false, true);
+            this(type, vectorCoercion, false, false, false, true, null);
         }
 
         public CoercionStep(RType type, boolean vectorCoercion, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-            this(type, vectorCoercion, preserveNames, preserveDimensions, preserveAttributes, true);
+            this(type, vectorCoercion, preserveNames, preserveDimensions, preserveAttributes, true, null);
         }
 
-        public CoercionStep(RType type, boolean vectorCoercion, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean preserveNonVector) {
+        public CoercionStep(RType type, boolean vectorCoercion, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean preserveNonVector, RBaseNode messageCallObj) {
             this.type = type;
             this.vectorCoercion = vectorCoercion;
             this.preserveNames = preserveNames;
             this.preserveAttributes = preserveAttributes;
             this.preserveDimensions = preserveDimensions;
             this.preserveNonVector = preserveNonVector;
+            this.messageCallObj = messageCallObj;
         }
 
         public RType getType() {
             return type;
         }
 
+        public RBaseNode getMessageCallObj() {
+            return messageCallObj;
+        }
+
         @Override
         public <D> D accept(PipelineStepVisitor<D> visitor) {
             return visitor.visit(this);
@@ -277,11 +295,13 @@ public abstract class PipelineStep<T, R> {
         private final Filter<?, ?> filter;
         private final PipelineStep<?, ?> trueBranch;
         private final PipelineStep<?, ?> falseBranch;
+        private final boolean returns;
 
-        public MapIfStep(Filter<?, ?> filter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch) {
+        public MapIfStep(Filter<?, ?> filter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch, boolean returns) {
             this.filter = filter;
             this.trueBranch = trueBranch;
             this.falseBranch = falseBranch;
+            this.returns = returns;
         }
 
         public Filter<?, ?> getFilter() {
@@ -296,6 +316,10 @@ public abstract class PipelineStep<T, R> {
             return falseBranch;
         }
 
+        public boolean isReturns() {
+            return returns;
+        }
+
         @Override
         public <D> D accept(PipelineStepVisitor<D> visitor) {
             return visitor.visit(this);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
index fdb073e07706cfb39c9828068c6bc43ab909cb89..09f6591a27fa2cbd11199422f7f26241eca7043a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java
@@ -22,6 +22,9 @@
  */
 package com.oracle.truffle.r.nodes.builtin.casts;
 
+import java.util.Optional;
+import java.util.function.Supplier;
+
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
 import com.oracle.truffle.r.nodes.builtin.ArgumentFilter;
 import com.oracle.truffle.r.nodes.builtin.ArgumentFilter.ArgumentTypeFilter;
@@ -61,6 +64,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapIfStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.NotNAStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.PipelineStepVisitor;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingAnalysisResult;
 import com.oracle.truffle.r.nodes.unary.BypassNode;
 import com.oracle.truffle.r.nodes.unary.BypassNodeGen.BypassDoubleNodeGen;
 import com.oracle.truffle.r.nodes.unary.BypassNodeGen.BypassIntegerNodeGen;
@@ -109,18 +113,32 @@ public final class PipelineToCastNode {
         // nop: static class
     }
 
-    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep) {
-        return convert(config, firstStep, PipelineConfig.getFilterFactory(), PipelineConfig.getMapperFactory());
+    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep, Optional<ForwardingAnalysisResult> fwdAnalysisResult) {
+        return convert(config, firstStep, PipelineConfig.getFilterFactory(), PipelineConfig.getMapperFactory(), fwdAnalysisResult);
     }
 
-    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep, ArgumentFilterFactory filterFactory, ArgumentMapperFactory mapperFactory) {
+    public static CastNode convert(PipelineConfig config, PipelineStep<?, ?> firstStep, ArgumentFilterFactory filterFactory, ArgumentMapperFactory mapperFactory,
+                    Optional<ForwardingAnalysisResult> fwdAnalysisResult) {
         if (firstStep == null) {
             return BypassNode.create(config, null, mapperFactory, null);
-        } else {
+        }
+
+        Supplier<CastNode> originalPipelineFactory = () -> {
             CastNodeFactory nodeFactory = new CastNodeFactory(filterFactory, mapperFactory, config.getDefaultDefaultMessage());
             SinglePrimitiveOptimization singleOptVisitor = new SinglePrimitiveOptimization(nodeFactory);
             CastNode headNode = convert(firstStep, singleOptVisitor);
             return singleOptVisitor.createBypassNode(config, headNode, mapperFactory);
+        };
+
+        if (!config.getValueForwarding()) {
+            return originalPipelineFactory.get();
+        }
+
+        ForwardingAnalysisResult fwdRes = fwdAnalysisResult.get();
+        if (fwdRes != null && fwdRes.isAnythingForwarded()) {
+            return ValueForwardingNodeGen.create(fwdRes, originalPipelineFactory);
+        } else {
+            return originalPipelineFactory.get();
         }
     }
 
@@ -402,19 +420,19 @@ public final class PipelineToCastNode {
             RType type = step.getType();
             switch (type) {
                 case Integer:
-                    return step.vectorCoercion ? CastIntegerNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes)
-                                    : CastIntegerBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
+                    return step.vectorCoercion ? CastIntegerNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, step.getMessageCallObj())
+                                    : CastIntegerBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, step.getMessageCallObj());
                 case Double:
-                    return step.vectorCoercion ? CastDoubleNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes)
-                                    : CastDoubleBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
+                    return step.vectorCoercion ? CastDoubleNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, step.getMessageCallObj())
+                                    : CastDoubleBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, step.getMessageCallObj());
                 case Character:
                     return step.vectorCoercion ? CastStringNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes)
                                     : CastStringBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
                 case Logical:
-                    return step.vectorCoercion ? CastLogicalNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes)
-                                    : CastLogicalBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
+                    return step.vectorCoercion ? CastLogicalNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, step.getMessageCallObj())
+                                    : CastLogicalBaseNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, step.getMessageCallObj());
                 case Complex:
-                    return CastComplexNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
+                    return CastComplexNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes, step.getMessageCallObj());
                 case Raw:
                     return CastRawNodeGen.create(step.preserveNames, step.preserveDimensions, step.preserveAttributes);
                 case Any:
@@ -440,7 +458,7 @@ public final class PipelineToCastNode {
             CastNode trueCastNode = PipelineToCastNode.convert(step.getTrueBranch(), this);
             CastNode falseCastNode = PipelineToCastNode.convert(step.getFalseBranch(), this);
             return ConditionalMapNode.create(condition, trueCastNode, falseCastNode, ResultForArg.TRUE.equals(step.getFilter().resultForNull()),
-                            ResultForArg.TRUE.equals(step.getFilter().resultForMissing()));
+                            ResultForArg.TRUE.equals(step.getFilter().resultForMissing()), step.isReturns());
         }
 
         private MessageData getDefaultErrorIfNull(MessageData message) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/ValueForwardingNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/ValueForwardingNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3baa1bb85619beb3f27fda1a4854efa424047f8
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/ValueForwardingNode.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.casts;
+
+import java.util.function.Supplier;
+
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingAnalysisResult;
+import com.oracle.truffle.r.nodes.unary.CastNode;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RComplex;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RNull;
+
+public abstract class ValueForwardingNode extends CastNode {
+
+    protected final ForwardingAnalysisResult forwardingResult;
+    private final Supplier<CastNode> pipelineFactory;
+
+    protected ValueForwardingNode(ForwardingAnalysisResult forwardingResult, Supplier<CastNode> pipelineFactory) {
+        this.forwardingResult = forwardingResult;
+        this.pipelineFactory = pipelineFactory;
+    }
+
+    @Specialization(guards = "forwardingResult.isNullForwarded()")
+    protected Object bypassNull(RNull x) {
+        return x;
+    }
+
+    @Specialization(guards = "forwardingResult.isMissingForwarded()")
+    protected Object bypassMissing(RMissing x) {
+        return x;
+    }
+
+    @Specialization(guards = "forwardingResult.isIntegerForwarded()")
+    protected int bypassInteger(int x) {
+        return x;
+    }
+
+    @Specialization(guards = "forwardingResult.isLogicalForwarded()")
+    protected byte bypassLogical(byte x) {
+        return x;
+    }
+
+    @Specialization(guards = "forwardingResult.isLogicalMappedToBoolean()")
+    protected boolean mapLogicalToBoolean(byte x) {
+        return RRuntime.fromLogical(x);
+    }
+
+    @Specialization(guards = "forwardingResult.isDoubleForwarded()")
+    protected double bypassDouble(double x) {
+        return x;
+    }
+
+    @Specialization(guards = "forwardingResult.isComplexForwarded()")
+    protected RComplex bypassComplex(RComplex x) {
+        return x;
+    }
+
+    @Specialization(guards = "forwardingResult.isStringForwarded()")
+    protected String bypassString(String x) {
+        return x;
+    }
+
+    protected CastNode createPipeline() {
+        return pipelineFactory.get();
+    }
+
+    @Specialization
+    protected Object executeOriginalPipeline(Object x, @Cached("createPipeline()") CastNode pipelineHeadNode) {
+        return pipelineHeadNode.execute(x);
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce9b228102be545d716a1ea095ac28a2b431ba7c
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.casts.analysis;
+
+import static com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingStatus.BLOCKED;
+import static com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingStatus.FORWARDED;
+import static com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingStatus.UNKNOWN;
+
+import com.oracle.truffle.r.nodes.builtin.casts.Filter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.AndFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter.Dim;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter.ElementAt;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter.NATest;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter.ScalarValue;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter.StringLength;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.CompareFilter.VectorSize;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.DoubleFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.MatrixFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.MissingFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter;
+import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
+import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean;
+import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapDoubleToInt;
+import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapToCharAt;
+import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapToValue;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.AttributableCoercionStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.BoxPrimitiveStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.CoercionStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.DefaultErrorStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.DefaultWarningStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FilterStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FindFirstStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapIfStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.NotNAStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.PipelineStepVisitor;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingStatus.Forwarded;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.RNull;
+
+public final class ForwardedValuesAnalyser implements PipelineStepVisitor<ForwardingAnalysisResult> {
+
+    private ForwardingAnalysisResult result = new ForwardingAnalysisResult().forwardAll();
+    private ForwardingAnalysisResult altResult = null;
+
+    public ForwardingAnalysisResult analyse(PipelineStep<?, ?> firstStep) {
+        firstStep.acceptPipeline(this);
+        ForwardingAnalysisResult mainRes = result;
+        if (altResult != null) {
+            mainRes = mainRes.or(altResult);
+        }
+        return mainRes;
+    }
+
+    private void addAlternativeResult(ForwardingAnalysisResult res) {
+        if (altResult == null) {
+            altResult = res;
+        } else {
+            altResult = altResult.or(res);
+        }
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(FindFirstStep<?, ?> step) {
+        ForwardingAnalysisResult localRes = new ForwardingAnalysisResult().blockAll().setForwardedType(step.getElementClass(), FORWARDED);
+        if (step.getDefaultValue() == RNull.instance) {
+            // see CoercedPhaseBuilder.findFirstOrNull()
+            localRes.setNull(FORWARDED);
+        }
+        result = result.and(localRes);
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(CoercionStep<?, ?> step) {
+        ForwardingAnalysisResult localRes = new ForwardingAnalysisResult().blockAll().setForwardedType(step.getType(), FORWARDED);
+        if (step.preserveNonVector) {
+            // i.e. preserve NULL and MISSING
+            localRes = localRes.setMissing(FORWARDED).setNull(FORWARDED);
+        }
+        result = result.and(localRes);
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(MapStep<?, ?> step) {
+        ForwardingAnalysisResult localRes = step.getMapper().accept(new Mapper.MapperVisitor<ForwardingAnalysisResult>() {
+
+            @Override
+            public ForwardingAnalysisResult visit(MapToValue<?, ?> mapper) {
+                return ForwardingAnalysisResult.INVALID;
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(MapByteToBoolean mapper) {
+                return new ForwardingAnalysisResult().blockAll().setForwardedType(RType.Logical, new Forwarded(mapper));
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(MapDoubleToInt mapper) {
+                return ForwardingAnalysisResult.INVALID;
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(MapToCharAt mapper) {
+                return ForwardingAnalysisResult.INVALID;
+            }
+        });
+        result = result.and(localRes);
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(MapIfStep<?, ?> mapIfStep) {
+        // analyze the true branch
+        ForwardingAnalysisResult trueBranchFwdRes;
+        PipelineStep<?, ?> trueBranchFirstStep = new FilterStep<>(mapIfStep.getFilter(), null, false);
+        ForwardedValuesAnalyser trueBranchFwdAnalyser = new ForwardedValuesAnalyser();
+        if (mapIfStep.getTrueBranch() != null) {
+            trueBranchFirstStep.setNext(mapIfStep.getTrueBranch());
+        }
+        trueBranchFwdRes = trueBranchFwdAnalyser.analyse(trueBranchFirstStep);
+
+        // analyze the false branch
+        ForwardingAnalysisResult falseBranchFwdRes;
+        ForwardedValuesAnalyser falseBranchFwdAnalyser = new ForwardedValuesAnalyser();
+        PipelineStep<?, ?> falseBranchFirstStep = new FilterStep<>(new NotFilter<>(mapIfStep.getFilter()), null, false);
+        if (mapIfStep.getFalseBranch() != null) {
+            falseBranchFirstStep.setNext(mapIfStep.getFalseBranch());
+        }
+        falseBranchFwdRes = falseBranchFwdAnalyser.analyse(falseBranchFirstStep);
+
+        if (mapIfStep.isReturns()) {
+            addAlternativeResult(result.and(trueBranchFwdRes));
+            result = result.and(falseBranchFwdRes);
+        } else {
+            result = result.and(trueBranchFwdRes.or(falseBranchFwdRes));
+        }
+
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(FilterStep<?, ?> step) {
+        class ForwardedValuesFilterVisitor implements Filter.FilterVisitor<ForwardingAnalysisResult> {
+
+            @Override
+            public ForwardingAnalysisResult visit(TypeFilter<?, ?> filter) {
+                ForwardingAnalysisResult res = new ForwardingAnalysisResult().blockAll();
+                if (filter.getExtraCondition() == null) {
+                    res = res.setForwardedType(filter.getType1(), FORWARDED);
+                } else {
+                    res = res.setForwardedType(filter.getType1(), UNKNOWN);
+                }
+                return res;
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(RTypeFilter<?> filter) {
+                return new ForwardingAnalysisResult().blockAll().setForwardedType(filter.getType(), FORWARDED);
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(CompareFilter<?> filter) {
+                return filter.getSubject().accept(new Filter.CompareFilter.SubjectVisitor<ForwardingAnalysisResult>() {
+
+                    @Override
+                    public ForwardingAnalysisResult visit(ScalarValue scalarValue, byte operation) {
+                        return new ForwardingAnalysisResult().blockAll().setForwardedType(scalarValue.type, UNKNOWN);
+                    }
+
+                    @Override
+                    public ForwardingAnalysisResult visit(NATest naTest, byte operation) {
+                        return new ForwardingAnalysisResult().blockAll().setForwardedType(naTest.type, UNKNOWN);
+                    }
+
+                    @Override
+                    public ForwardingAnalysisResult visit(StringLength stringLength, byte operation) {
+                        return new ForwardingAnalysisResult().blockAll().setForwardedType(RType.Character, UNKNOWN);
+                    }
+
+                    @Override
+                    public ForwardingAnalysisResult visit(VectorSize vectorSize, byte operation) {
+                        if (vectorSize.size == 0 && operation == CompareFilter.EQ) {
+                            return new ForwardingAnalysisResult().blockAll().setNull(FORWARDED);
+                        } else if (vectorSize.size == 1 && (operation == CompareFilter.EQ || operation == CompareFilter.GT || operation == CompareFilter.GE)) {
+                            return new ForwardingAnalysisResult().forwardAll().setNull(BLOCKED).setMissing(BLOCKED);
+                        } else if (vectorSize.size > 1 && (operation == CompareFilter.EQ || operation == CompareFilter.GT || operation == CompareFilter.GE)) {
+                            return new ForwardingAnalysisResult().blockAll();
+                        } else if (vectorSize.size > 1 && (operation == CompareFilter.LE || operation == CompareFilter.LT)) {
+                            return new ForwardingAnalysisResult().forwardAll().setMissing(BLOCKED);
+                        } else {
+                            return new ForwardingAnalysisResult().unknownAll().setMissing(BLOCKED);
+                        }
+                    }
+
+                    @Override
+                    public ForwardingAnalysisResult visit(ElementAt elementAt, byte operation) {
+                        if (elementAt.index == 0) {
+                            return new ForwardingAnalysisResult().blockAll().setForwardedType(elementAt.type, UNKNOWN);
+                        } else {
+                            return new ForwardingAnalysisResult().blockAll();
+                        }
+                    }
+
+                    @Override
+                    public ForwardingAnalysisResult visit(Dim dim, byte operation) {
+                        return new ForwardingAnalysisResult().blockAll();
+                    }
+                }, filter.getOperation());
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(AndFilter<?, ?> filter) {
+                ForwardedValuesFilterVisitor leftVis = new ForwardedValuesFilterVisitor();
+                ForwardedValuesFilterVisitor rightVis = new ForwardedValuesFilterVisitor();
+                ForwardingAnalysisResult leftResult = filter.getLeft().accept(leftVis);
+                ForwardingAnalysisResult rightResult = filter.getRight().accept(rightVis);
+                return leftResult.and(rightResult);
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(OrFilter<?> filter) {
+                ForwardedValuesFilterVisitor leftVis = new ForwardedValuesFilterVisitor();
+                ForwardedValuesFilterVisitor rightVis = new ForwardedValuesFilterVisitor();
+                ForwardingAnalysisResult leftResult = filter.getLeft().accept(leftVis);
+                ForwardingAnalysisResult rightResult = filter.getRight().accept(rightVis);
+                return leftResult.or(rightResult);
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(NotFilter<?> filter) {
+                ForwardedValuesFilterVisitor vis = new ForwardedValuesFilterVisitor();
+                return filter.getFilter().accept(vis).not();
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(MatrixFilter<?> filter) {
+                return new ForwardingAnalysisResult().forwardAll();
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(DoubleFilter filter) {
+                return new ForwardingAnalysisResult().blockAll().setForwardedType(RType.Double, UNKNOWN);
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(NullFilter filter) {
+                return new ForwardingAnalysisResult().blockAll().setNull(FORWARDED);
+            }
+
+            @Override
+            public ForwardingAnalysisResult visit(MissingFilter filter) {
+                return new ForwardingAnalysisResult().blockAll().setMissing(FORWARDED);
+            }
+        }
+        ForwardingAnalysisResult localRes = step.getFilter().accept(new ForwardedValuesFilterVisitor());
+        result = result.and(localRes);
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(NotNAStep<?> step) {
+        result = result.and(new ForwardingAnalysisResult().unknownAll().setNull(FORWARDED).setMissing(FORWARDED));
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(DefaultErrorStep<?> step) {
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(DefaultWarningStep<?> step) {
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(BoxPrimitiveStep<?> step) {
+        // TODO
+        result = ForwardingAnalysisResult.INVALID;
+        return result;
+    }
+
+    @Override
+    public ForwardingAnalysisResult visit(AttributableCoercionStep<?> step) {
+        // TODO
+        result = ForwardingAnalysisResult.INVALID;
+        return result;
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardingAnalysisResult.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardingAnalysisResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..353156736aef1612b6b8550f02327fc8dd858969
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardingAnalysisResult.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.casts.analysis;
+
+import static com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingStatus.BLOCKED;
+import static com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingStatus.FORWARDED;
+import static com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingStatus.UNKNOWN;
+
+import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.RComplex;
+
+public final class ForwardingAnalysisResult {
+
+    public final ForwardingStatus integerForwarded;
+    public final ForwardingStatus logicalForwarded;
+    public final ForwardingStatus doubleForwarded;
+    public final ForwardingStatus complexForwarded;
+    public final ForwardingStatus stringForwarded;
+    public final ForwardingStatus nullForwarded;
+    public final ForwardingStatus missingForwarded;
+    public final boolean invalid;
+
+    static final ForwardingAnalysisResult INVALID = new ForwardingAnalysisResult(UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, true);
+
+    ForwardingAnalysisResult() {
+        this(UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, false);
+    }
+
+    private ForwardingAnalysisResult(ForwardingStatus integerForwarded,
+                    ForwardingStatus logicalForwarded,
+                    ForwardingStatus doubleForwarded,
+                    ForwardingStatus complexForwarded,
+                    ForwardingStatus stringForwarded,
+                    ForwardingStatus nullForwarded,
+                    ForwardingStatus missingForwarded,
+                    boolean invalid) {
+        this.integerForwarded = integerForwarded;
+        this.logicalForwarded = logicalForwarded;
+        this.doubleForwarded = doubleForwarded;
+        this.complexForwarded = complexForwarded;
+        this.stringForwarded = stringForwarded;
+        this.nullForwarded = nullForwarded;
+        this.missingForwarded = missingForwarded;
+        this.invalid = invalid;
+    }
+
+    public boolean isNullForwarded() {
+        return !invalid && nullForwarded.isForwarded();
+    }
+
+    public boolean isMissingForwarded() {
+        return !invalid && missingForwarded.isForwarded();
+    }
+
+    public boolean isIntegerForwarded() {
+        return !invalid && integerForwarded.isForwarded();
+    }
+
+    public boolean isLogicalForwarded() {
+        return !invalid && logicalForwarded.isForwarded();
+    }
+
+    public boolean isLogicalMappedToBoolean() {
+        return !invalid && logicalForwarded.mapper == MapByteToBoolean.INSTANCE;
+    }
+
+    public boolean isDoubleForwarded() {
+        return !invalid && doubleForwarded.isForwarded();
+    }
+
+    public boolean isComplexForwarded() {
+        return !invalid && complexForwarded.isForwarded();
+    }
+
+    public boolean isStringForwarded() {
+        return !invalid && stringForwarded.isForwarded();
+    }
+
+    public boolean isAnythingForwarded() {
+        return isNullForwarded() || isMissingForwarded() || isIntegerForwarded() || isLogicalForwarded() || isDoubleForwarded() || isComplexForwarded() || isStringForwarded();
+    }
+
+    ForwardingAnalysisResult setForwardedType(Class<?> tp, ForwardingStatus status) {
+        if (invalid) {
+            return this;
+        }
+
+        if (Integer.class == tp || int.class == tp) {
+            return new ForwardingAnalysisResult(status,
+                            logicalForwarded,
+                            doubleForwarded,
+                            complexForwarded,
+                            stringForwarded,
+                            nullForwarded,
+                            missingForwarded,
+                            invalid);
+        } else if (Byte.class == tp || byte.class == tp) {
+            return new ForwardingAnalysisResult(integerForwarded,
+                            status,
+                            doubleForwarded,
+                            complexForwarded,
+                            stringForwarded,
+                            nullForwarded,
+                            missingForwarded,
+                            invalid);
+        } else if (Double.class == tp || double.class == tp) {
+            return new ForwardingAnalysisResult(integerForwarded,
+                            logicalForwarded,
+                            status,
+                            complexForwarded,
+                            stringForwarded,
+                            nullForwarded,
+                            missingForwarded,
+                            invalid);
+        } else if (RComplex.class == tp) {
+            return new ForwardingAnalysisResult(integerForwarded,
+                            logicalForwarded,
+                            doubleForwarded,
+                            status,
+                            stringForwarded,
+                            nullForwarded,
+                            missingForwarded,
+                            invalid);
+        } else if (String.class == tp) {
+            return new ForwardingAnalysisResult(integerForwarded,
+                            logicalForwarded,
+                            doubleForwarded,
+                            complexForwarded,
+                            status,
+                            nullForwarded,
+                            missingForwarded,
+                            invalid);
+        } else if (Object.class == tp) {
+            return new ForwardingAnalysisResult(FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            invalid);
+        } else {
+            return this;
+        }
+    }
+
+    ForwardingAnalysisResult setForwardedType(RType tp, ForwardingStatus status) {
+        if (invalid) {
+            return this;
+        }
+
+        switch (tp) {
+            case Integer:
+                return new ForwardingAnalysisResult(status,
+                                logicalForwarded,
+                                doubleForwarded,
+                                complexForwarded,
+                                stringForwarded,
+                                nullForwarded,
+                                missingForwarded,
+                                invalid);
+            case Logical:
+                return new ForwardingAnalysisResult(integerForwarded,
+                                status,
+                                doubleForwarded,
+                                complexForwarded,
+                                stringForwarded,
+                                nullForwarded,
+                                missingForwarded,
+                                invalid);
+            case Double:
+                return new ForwardingAnalysisResult(integerForwarded,
+                                logicalForwarded,
+                                status,
+                                complexForwarded,
+                                stringForwarded,
+                                nullForwarded,
+                                missingForwarded,
+                                invalid);
+            case Complex:
+                return new ForwardingAnalysisResult(integerForwarded,
+                                logicalForwarded,
+                                doubleForwarded,
+                                status,
+                                stringForwarded,
+                                nullForwarded,
+                                missingForwarded,
+                                invalid);
+            case Character:
+                return new ForwardingAnalysisResult(integerForwarded,
+                                logicalForwarded,
+                                doubleForwarded,
+                                complexForwarded,
+                                status,
+                                nullForwarded,
+                                missingForwarded,
+                                invalid);
+            default:
+                return this;
+        }
+    }
+
+    ForwardingAnalysisResult and(ForwardingAnalysisResult other) {
+        if (this.invalid || other.invalid) {
+            return ForwardingAnalysisResult.INVALID;
+        } else {
+            return new ForwardingAnalysisResult(this.integerForwarded.and(other.integerForwarded),
+                            this.logicalForwarded.and(other.logicalForwarded),
+                            this.doubleForwarded.and(other.doubleForwarded),
+                            this.complexForwarded.and(other.complexForwarded),
+                            this.stringForwarded.and(other.stringForwarded),
+                            this.nullForwarded.and(other.nullForwarded),
+                            this.missingForwarded.and(other.missingForwarded),
+                            false);
+        }
+    }
+
+    ForwardingAnalysisResult or(ForwardingAnalysisResult other) {
+        if (this.invalid) {
+            return other;
+        } else if (other.invalid) {
+            return this;
+        } else {
+            return new ForwardingAnalysisResult(this.integerForwarded.or(other.integerForwarded),
+                            this.logicalForwarded.or(other.logicalForwarded),
+                            this.doubleForwarded.or(other.doubleForwarded),
+                            this.complexForwarded.or(other.complexForwarded),
+                            this.stringForwarded.or(other.stringForwarded),
+                            this.nullForwarded.or(other.nullForwarded),
+                            this.missingForwarded.or(other.missingForwarded),
+                            false);
+        }
+    }
+
+    ForwardingAnalysisResult not() {
+        if (this.invalid) {
+            return this;
+        } else {
+            return new ForwardingAnalysisResult(this.integerForwarded.not(),
+                            this.logicalForwarded.not(),
+                            this.doubleForwarded.not(),
+                            this.complexForwarded.not(),
+                            this.stringForwarded.not(),
+                            this.nullForwarded.not(),
+                            this.missingForwarded.not(),
+                            false);
+        }
+    }
+
+    ForwardingAnalysisResult forwardAll() {
+        if (this.invalid) {
+            return this;
+        } else {
+            return new ForwardingAnalysisResult(FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            FORWARDED,
+                            false);
+        }
+    }
+
+    ForwardingAnalysisResult blockAll() {
+        if (this.invalid) {
+            return this;
+        } else {
+            return new ForwardingAnalysisResult(BLOCKED,
+                            BLOCKED,
+                            BLOCKED,
+                            BLOCKED,
+                            BLOCKED,
+                            BLOCKED,
+                            BLOCKED,
+                            false);
+        }
+    }
+
+    ForwardingAnalysisResult unknownAll() {
+        if (this.invalid) {
+            return this;
+        } else {
+            return new ForwardingAnalysisResult(UNKNOWN,
+                            UNKNOWN,
+                            UNKNOWN,
+                            UNKNOWN,
+                            UNKNOWN,
+                            UNKNOWN,
+                            UNKNOWN,
+                            false);
+        }
+    }
+
+    ForwardingAnalysisResult setNull(ForwardingStatus status) {
+        if (this.invalid) {
+            return this;
+        } else {
+            return new ForwardingAnalysisResult(this.integerForwarded,
+                            this.logicalForwarded,
+                            this.doubleForwarded,
+                            this.complexForwarded,
+                            this.stringForwarded,
+                            status,
+                            this.missingForwarded,
+                            false);
+        }
+    }
+
+    ForwardingAnalysisResult setMissing(ForwardingStatus status) {
+        if (this.invalid) {
+            return this;
+        } else {
+            return new ForwardingAnalysisResult(this.integerForwarded,
+                            this.logicalForwarded,
+                            this.doubleForwarded,
+                            this.complexForwarded,
+                            this.stringForwarded,
+                            this.nullForwarded,
+                            status,
+                            false);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardingStatus.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardingStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..a59b7c04358ce5fb1082ad0ce8fc5e88288ccd3d
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardingStatus.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.casts.analysis;
+
+import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
+import com.oracle.truffle.r.runtime.RInternalError;
+
+public abstract class ForwardingStatus {
+
+    public static final class Forwarded extends ForwardingStatus {
+        Forwarded(Mapper<?, ?> mapper) {
+            super((byte) 1, mapper);
+        }
+    }
+
+    public static final ForwardingStatus BLOCKED = new ForwardingStatus((byte) 0, null) {
+    };
+    public static final ForwardingStatus UNKNOWN = new ForwardingStatus((byte) -1, null) {
+    };
+    public static final ForwardingStatus FORWARDED = new Forwarded(null);
+
+    final Mapper<?, ?> mapper;
+    private final byte flag;
+
+    protected ForwardingStatus(byte flag, Mapper<?, ?> mapper) {
+        this.flag = flag;
+        this.mapper = mapper;
+    }
+
+    private static byte and(byte x1, byte x2) {
+        if (x1 < 0 && x2 < 0) {
+            return -1;
+        } else {
+            return (byte) (x1 * x2);
+        }
+    }
+
+    private static byte or(byte x1, byte x2) {
+        if (x1 == 0 && x2 == 0) {
+            return 0;
+        } else {
+            return x1 + x2 >= 0 ? (byte) 1 : (byte) -1;
+        }
+    }
+
+    private static byte not(byte x) {
+        if (x < 0) {
+            return -1;
+        } else {
+            return x == 0 ? (byte) 1 : (byte) 0;
+        }
+    }
+
+    static ForwardingStatus fromFlag(byte flag) {
+        return fromFlag(flag, null);
+    }
+
+    static ForwardingStatus fromFlag(byte flag, Mapper<?, ?> mapper) {
+        switch (flag) {
+            case -1:
+                return UNKNOWN;
+            case 0:
+                return BLOCKED;
+            case 1:
+                return mapper == null ? FORWARDED : new Forwarded(mapper);
+            default:
+                throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    ForwardingStatus and(ForwardingStatus other) {
+        if (this.mapper != null && other.mapper != null) {
+            // only one mapper per type is supported in this analysis
+            return UNKNOWN;
+        }
+        return fromFlag(and(this.flag, other.flag), this.mapper != null ? this.mapper : other.mapper);
+    }
+
+    ForwardingStatus or(ForwardingStatus other) {
+        return fromFlag(or(this.flag, other.flag));
+    }
+
+    ForwardingStatus not() {
+        return fromFlag(not(this.flag));
+    }
+
+    public boolean isForwarded() {
+        return flag == (byte) 1 && mapper == null;
+    }
+
+    public boolean isBlocked() {
+        return flag == (byte) 0;
+    }
+
+    public boolean isUnknown() {
+        return flag == (byte) -1;
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/ArgCastBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/ArgCastBuilder.java
index 6ff73bb1fab346efdcf8b842956a56366326cd5a..4d2390aeb594fc9a4efe021acc8f24dbdf3f93fb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/ArgCastBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/ArgCastBuilder.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.builtin.casts.fluent;
 import java.util.function.Function;
 
 import com.oracle.truffle.r.nodes.builtin.casts.Filter;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
@@ -78,4 +79,8 @@ public class ArgCastBuilder<T, THIS> {
     public <R, THAT extends ArgCastBuilder<R, THAT>> THAT alias(Function<THIS, THAT> aliaser) {
         return aliaser.apply((THIS) this);
     }
+
+    public CastNode buildCastNode() {
+        return builder.buildNode();
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/CastNodeBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/CastNodeBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..aae3576a5a8c733cb5316a53df9dde46a134374f
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/CastNodeBuilder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.casts.fluent;
+
+/**
+ * Can be used to construct a cast node outside of the FastR builtins framework. The cast node can
+ * be then used to cast anything, not only arguments.
+ */
+public final class CastNodeBuilder {
+    public static PreinitialPhaseBuilder newCastBuilder(String argName) {
+        return new PipelineBuilder(argName).fluent();
+    }
+
+    public static PreinitialPhaseBuilder newCastBuilder() {
+        return newCastBuilder("");
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/CoercedPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/CoercedPhaseBuilder.java
index 016eef5e7a23b0e94f1a0679722288ce5dd11493..5ced98be0f64a429c7b6debd151e8433d540bf00 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/CoercedPhaseBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/CoercedPhaseBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.builtin.casts.fluent;
 
 import com.oracle.truffle.r.nodes.builtin.casts.Filter;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
@@ -89,6 +90,11 @@ public final class CoercedPhaseBuilder<T extends RAbstractVector, S> extends Arg
         return new HeadPhaseBuilder<>(pipelineBuilder());
     }
 
+    public HeadPhaseBuilder<S> findFirstOrNull() {
+        pipelineBuilder().appendFindFirst(RNull.instance, elementClass, null, null, null);
+        return new HeadPhaseBuilder<>(pipelineBuilder());
+    }
+
     public CoercedPhaseBuilder<T, S> mustBe(Filter<? super T, ? extends T> argFilter, RBaseNode callObj, RError.Message message, Object... messageArgs) {
         pipelineBuilder().appendMustBeStep(argFilter, callObj, message, messageArgs);
         return this;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/HeadPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/HeadPhaseBuilder.java
index 7248195f5929cd72ffc74fde254075821df3d0bb..6d0d72eb972efbd59ccb569ab971268fa2a39f90 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/HeadPhaseBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/HeadPhaseBuilder.java
@@ -46,23 +46,48 @@ public final class HeadPhaseBuilder<T> extends ArgCastBuilder<T, HeadPhaseBuilde
         return new HeadPhaseBuilder<>(pipelineBuilder());
     }
 
+    public HeadPhaseBuilder<Object> returnIf(Filter<? super T, ?> argFilter) {
+        pipelineBuilder().appendMapIf(argFilter, (PipelineStep<?, ?>) null, (PipelineStep<?, ?>) null, true);
+        return new HeadPhaseBuilder<>(pipelineBuilder());
+    }
+
     public <S extends T, R> HeadPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper);
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, false);
+        return new HeadPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> HeadPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, true);
         return new HeadPhaseBuilder<>(pipelineBuilder());
     }
 
     public <S extends T, R> HeadPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper, Mapper<T, ?> falseBranchMapper) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, falseBranchMapper);
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, falseBranchMapper, false);
+        return new HeadPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> HeadPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper, Mapper<T, ?> falseBranchMapper) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, falseBranchMapper, true);
         return new HeadPhaseBuilder<>(pipelineBuilder());
     }
 
     public <S extends T, R> HeadPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, PipelineStep<S, ?> trueBranch) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranch);
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, false);
+        return new HeadPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> HeadPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, PipelineStep<S, ?> trueBranch) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, true);
         return new HeadPhaseBuilder<>(pipelineBuilder());
     }
 
     public <S extends T, R> HeadPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, PipelineStep<S, R> trueBranch, PipelineStep<T, ?> falseBranch) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranch, falseBranch);
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, falseBranch, false);
+        return new HeadPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> HeadPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, PipelineStep<S, R> trueBranch, PipelineStep<T, ?> falseBranch) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, falseBranch, true);
         return new HeadPhaseBuilder<>(pipelineBuilder());
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
index 9b0cbf6d2917fa6616a161c70cb4556958d1856a..58fe88bbdc18017e032a9af5d292c7a4e705dc6a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 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.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -98,23 +99,48 @@ public class InitialPhaseBuilder<T> extends ArgCastBuilder<T, InitialPhaseBuilde
         return new InitialPhaseBuilder<>(pipelineBuilder());
     }
 
+    public InitialPhaseBuilder<Object> returnIf(Filter<? super T, ?> argFilter) {
+        pipelineBuilder().appendMapIf(argFilter, (PipelineStep<?, ?>) null, (PipelineStep<?, ?>) null, true);
+        return new InitialPhaseBuilder<>(pipelineBuilder());
+    }
+
     public <S extends T, R> InitialPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper);
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, false);
+        return new InitialPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> InitialPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, true);
         return new InitialPhaseBuilder<>(pipelineBuilder());
     }
 
     public <S extends T, R> InitialPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper, Mapper<T, ?> falseBranchMapper) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, falseBranchMapper);
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, falseBranchMapper, false);
+        return new InitialPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> InitialPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, Mapper<S, R> trueBranchMapper, Mapper<T, ?> falseBranchMapper) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranchMapper, falseBranchMapper, true);
         return new InitialPhaseBuilder<>(pipelineBuilder());
     }
 
     public <S extends T, R> InitialPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, PipelineStep<?, ?> trueBranch) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranch);
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, false);
+        return new InitialPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> InitialPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, PipelineStep<?, ?> trueBranch) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, true);
         return new InitialPhaseBuilder<>(pipelineBuilder());
     }
 
     public <S extends T, R> InitialPhaseBuilder<Object> mapIf(Filter<? super T, S> argFilter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch) {
-        pipelineBuilder().appendMapIf(argFilter, trueBranch, falseBranch);
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, falseBranch, false);
+        return new InitialPhaseBuilder<>(pipelineBuilder());
+    }
+
+    public <S extends T, R> InitialPhaseBuilder<Object> returnIf(Filter<? super T, S> argFilter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch) {
+        pipelineBuilder().appendMapIf(argFilter, trueBranch, falseBranch, true);
         return new InitialPhaseBuilder<>(pipelineBuilder());
     }
 
@@ -149,29 +175,53 @@ public class InitialPhaseBuilder<T> extends ArgCastBuilder<T, InitialPhaseBuilde
     }
 
     public CoercedPhaseBuilder<RAbstractIntVector, Integer> asIntegerVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        pipelineBuilder().appendAsVector(RType.Integer, preserveNames, preserveDimensions, preserveAttributes);
+        return asIntegerVector(preserveNames, preserveDimensions, preserveAttributes, null);
+    }
+
+    public CoercedPhaseBuilder<RAbstractIntVector, Integer> asIntegerVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+        pipelineBuilder().appendAsVector(RType.Integer, preserveNames, preserveDimensions, preserveAttributes, messageCallerObj);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), Integer.class);
     }
 
+    public CoercedPhaseBuilder<RAbstractIntVector, Integer> asIntegerVector(RBaseNode messageCallerObj) {
+        return asIntegerVector(false, false, false, messageCallerObj);
+    }
+
     public CoercedPhaseBuilder<RAbstractIntVector, Integer> asIntegerVector() {
         return asIntegerVector(false, false, false);
     }
 
     public CoercedPhaseBuilder<RAbstractDoubleVector, Double> asDoubleVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        pipelineBuilder().appendAsVector(RType.Double, preserveNames, preserveDimensions, preserveAttributes);
+        return asDoubleVector(preserveNames, preserveDimensions, preserveAttributes, null);
+    }
+
+    public CoercedPhaseBuilder<RAbstractDoubleVector, Double> asDoubleVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+        pipelineBuilder().appendAsVector(RType.Double, preserveNames, preserveDimensions, preserveAttributes, messageCallerObj);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), Double.class);
     }
 
+    public CoercedPhaseBuilder<RAbstractDoubleVector, Double> asDoubleVector(RBaseNode messageCallerObj) {
+        return asDoubleVector(false, false, false, messageCallerObj);
+    }
+
     public CoercedPhaseBuilder<RAbstractDoubleVector, Double> asDoubleVector() {
         return asDoubleVector(false, false, false);
     }
 
-    public CoercedPhaseBuilder<RAbstractDoubleVector, Byte> asLogicalVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        pipelineBuilder().appendAsVector(RType.Logical, preserveNames, preserveDimensions, preserveAttributes);
+    public CoercedPhaseBuilder<RAbstractLogicalVector, Byte> asLogicalVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+        pipelineBuilder().appendAsVector(RType.Logical, preserveNames, preserveDimensions, preserveAttributes, messageCallerObj);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), Byte.class);
     }
 
-    public CoercedPhaseBuilder<RAbstractDoubleVector, Byte> asLogicalVector() {
+    public CoercedPhaseBuilder<RAbstractLogicalVector, Byte> asLogicalVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return asLogicalVector(preserveNames, preserveDimensions, preserveAttributes, null);
+    }
+
+    public CoercedPhaseBuilder<RAbstractLogicalVector, Byte> asLogicalVector(RBaseNode messageCallerObj) {
+        return asLogicalVector(false, false, false, messageCallerObj);
+    }
+
+    public CoercedPhaseBuilder<RAbstractLogicalVector, Byte> asLogicalVector() {
         return asLogicalVector(false, false, false);
     }
 
@@ -185,10 +235,18 @@ public class InitialPhaseBuilder<T> extends ArgCastBuilder<T, InitialPhaseBuilde
     }
 
     public CoercedPhaseBuilder<RAbstractComplexVector, RComplex> asComplexVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        pipelineBuilder().appendAsVector(RType.Complex, preserveNames, preserveDimensions, preserveAttributes);
+        return asComplexVector(preserveNames, preserveDimensions, preserveAttributes, null);
+    }
+
+    public CoercedPhaseBuilder<RAbstractComplexVector, RComplex> asComplexVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+        pipelineBuilder().appendAsVector(RType.Complex, preserveNames, preserveDimensions, preserveAttributes, messageCallerObj);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), RComplex.class);
     }
 
+    public CoercedPhaseBuilder<RAbstractComplexVector, RComplex> asComplexVector(RBaseNode messageCallerObj) {
+        return asComplexVector(false, false, false, messageCallerObj);
+    }
+
     public CoercedPhaseBuilder<RAbstractComplexVector, RComplex> asComplexVector() {
         return asComplexVector(false, false, false);
     }
@@ -203,17 +261,17 @@ public class InitialPhaseBuilder<T> extends ArgCastBuilder<T, InitialPhaseBuilde
     }
 
     public CoercedPhaseBuilder<RAbstractVector, Object> asVector() {
-        pipelineBuilder().appendAsVector(false, false, false, true);
+        pipelineBuilder().appendAsVector(false, false, false, true, null);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), Object.class);
     }
 
     public CoercedPhaseBuilder<RAbstractVector, Object> asVector(boolean preserveNonVector) {
-        pipelineBuilder().appendAsVector(false, false, false, preserveNonVector);
+        pipelineBuilder().appendAsVector(false, false, false, preserveNonVector, null);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), Object.class);
     }
 
     public CoercedPhaseBuilder<RAbstractVector, Object> asVectorPreserveAttrs(boolean preserveNonVector) {
-        pipelineBuilder().appendAsVector(false, false, true, preserveNonVector);
+        pipelineBuilder().appendAsVector(false, false, true, preserveNonVector, null);
         return new CoercedPhaseBuilder<>(pipelineBuilder(), Object.class);
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
index f2dee59fd83941231c746f099fde11090ce8d07e..c5f4ba8394fb5725330bde49bc658ff886910af8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,9 @@
  */
 package com.oracle.truffle.r.nodes.builtin.casts.fluent;
 
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+
 import com.oracle.truffle.r.nodes.builtin.casts.Filter;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
 import com.oracle.truffle.r.nodes.builtin.casts.MessageData;
@@ -35,6 +38,10 @@ import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FindFirstStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapIfStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.NotNAStep;
+import com.oracle.truffle.r.nodes.builtin.casts.PipelineToCastNode;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardedValuesAnalyser;
+import com.oracle.truffle.r.nodes.builtin.casts.analysis.ForwardingAnalysisResult;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
@@ -48,26 +55,18 @@ public final class PipelineBuilder {
 
     private final PipelineConfigBuilder pcb;
     private ChainBuilder<?> chainBuilder;
+    private final AtomicReference<Optional<ForwardingAnalysisResult>> fwdAnalysisResult = new AtomicReference<>();
 
-    public PipelineBuilder(PipelineConfigBuilder pcb) {
-        this.pcb = pcb;
-    }
-
-    // TODO: can be package private once the legacy API is removed
-    public void append(PipelineStep<?, ?> step) {
-        if (chainBuilder == null) {
-            chainBuilder = new ChainBuilder<>(step);
-        } else {
-            chainBuilder.addStep(step);
-        }
+    public PipelineBuilder(String argumentName) {
+        this.pcb = new PipelineConfigBuilder(argumentName);
     }
 
-    public PipelineConfigBuilder getPipelineConfig() {
-        return pcb;
+    public CastNode buildNode() {
+        return PipelineToCastNode.convert(pcb.build(), getFirstStep(), getFwdAnalysisResult());
     }
 
-    public PipelineStep<?, ?> getFirstStep() {
-        return chainBuilder != null ? chainBuilder.getFirstStep() : null;
+    public PreinitialPhaseBuilder fluent() {
+        return new PreinitialPhaseBuilder(this);
     }
 
     public void appendBoxPrimitive() {
@@ -82,33 +81,37 @@ public final class PipelineBuilder {
         append(new AttributableCoercionStep<>(preserveNames, preserveDimensions, preserveAttributes));
     }
 
-    public void appendAsVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean preserveNonVector) {
-        append(new CoercionStep<>(RType.Any, true, preserveNames, preserveDimensions, preserveAttributes, preserveNonVector));
+    public void appendAsVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean preserveNonVector, RBaseNode messageCallerObj) {
+        append(new CoercionStep<>(RType.Any, true, preserveNames, preserveDimensions, preserveAttributes, preserveNonVector, messageCallerObj));
     }
 
-    public void appendAsVector(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+    public void appendAsVector(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
         assert type == RType.Integer || type == RType.Double || type == RType.Complex || type == RType.Character || type == RType.Logical || type == RType.Raw;
-        append(new CoercionStep<>(type, true, preserveNames, preserveDimensions, preserveAttributes));
+        append(new CoercionStep<>(type, true, preserveNames, preserveDimensions, preserveAttributes, true, messageCallerObj));
+    }
+
+    public void appendAsVector(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        appendAsVector(type, preserveNames, preserveDimensions, preserveAttributes, null);
     }
 
     public void appendNotNA(Object naReplacement, RBaseNode callObj, Message message, Object[] messageArgs) {
         append(new NotNAStep<>(naReplacement, createMessage(callObj, message, messageArgs)));
     }
 
-    public void appendMapIf(Filter<?, ?> argFilter, Mapper<?, ?> trueBranchMapper) {
-        appendMapIf(argFilter, trueBranchMapper, null);
+    public void appendMapIf(Filter<?, ?> argFilter, Mapper<?, ?> trueBranchMapper, boolean returns) {
+        appendMapIf(argFilter, trueBranchMapper, null, returns);
     }
 
-    public void appendMapIf(Filter<?, ?> argFilter, Mapper<?, ?> trueBranchMapper, Mapper<?, ?> falseBranchMapper) {
-        appendMapIf(argFilter, new MapStep<>(trueBranchMapper), falseBranchMapper == null ? null : new MapStep<>(falseBranchMapper));
+    public void appendMapIf(Filter<?, ?> argFilter, Mapper<?, ?> trueBranchMapper, Mapper<?, ?> falseBranchMapper, boolean returns) {
+        appendMapIf(argFilter, new MapStep<>(trueBranchMapper), falseBranchMapper == null ? null : new MapStep<>(falseBranchMapper), returns);
     }
 
-    public void appendMapIf(Filter<?, ?> argFilter, PipelineStep<?, ?> trueBranch) {
-        appendMapIf(argFilter, trueBranch, null);
+    public void appendMapIf(Filter<?, ?> argFilter, PipelineStep<?, ?> trueBranch, boolean returns) {
+        appendMapIf(argFilter, trueBranch, null, returns);
     }
 
-    public void appendMapIf(Filter<?, ?> argFilter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch) {
-        append(new MapIfStep<>(argFilter, trueBranch, falseBranch));
+    public void appendMapIf(Filter<?, ?> argFilter, PipelineStep<?, ?> trueBranch, PipelineStep<?, ?> falseBranch, boolean returns) {
+        append(new MapIfStep<>(argFilter, trueBranch, falseBranch, returns));
     }
 
     public void appendMap(Mapper<?, ?> mapFn) {
@@ -138,4 +141,40 @@ public final class PipelineBuilder {
     private static MessageData createMessage(RBaseNode callObj, Message message, Object[] messageArgs) {
         return message == null ? null : new MessageData(callObj, message, messageArgs);
     }
+
+    PipelineConfigBuilder getPipelineConfig() {
+        return pcb;
+    }
+
+    private PipelineStep<?, ?> getFirstStep() {
+        return chainBuilder != null ? chainBuilder.getFirstStep() : null;
+    }
+
+    private void append(PipelineStep<?, ?> step) {
+        if (chainBuilder == null) {
+            chainBuilder = new ChainBuilder<>(step);
+        } else {
+            chainBuilder.addStep(step);
+        }
+    }
+
+    public Optional<ForwardingAnalysisResult> getFwdAnalysisResult() {
+        Optional<ForwardingAnalysisResult> res = fwdAnalysisResult.get();
+        if (res == null) {
+            ForwardedValuesAnalyser fwdAnalyser = new ForwardedValuesAnalyser();
+            PipelineStep<?, ?> firstStep = getFirstStep();
+            if (firstStep == null) {
+                res = Optional.empty();
+            } else {
+                res = Optional.of(fwdAnalyser.analyse(firstStep));
+            }
+            if (fwdAnalysisResult.compareAndSet(null, res)) {
+                return res;
+            } else {
+                return fwdAnalysisResult.get();
+            }
+        } else {
+            return res;
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java
index 79fd4651d2c321223ea9ad81679ef4e6ba7228ee..2492ae892249550551e442523159521b161e828b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PipelineConfigBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,14 +22,12 @@
  */
 package com.oracle.truffle.r.nodes.builtin.casts.fluent;
 
-import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef;
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
 import com.oracle.truffle.r.nodes.builtin.casts.MessageData;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineConfig;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * Provides fluent API for building the pipeline configuration {@link PipelineConfig}: default
@@ -45,9 +43,7 @@ public final class PipelineConfigBuilder {
     private Mapper<? super RNull, ?> nullMapper;
     private MessageData missingMsg;
     private MessageData nullMsg;
-
-    // TODO: to be removed with legacy API
-    private boolean wasLegacyAsVectorCall = false;
+    private boolean valueForwarding = true;
 
     public PipelineConfigBuilder(String argumentName) {
         this.argumentName = argumentName;
@@ -56,15 +52,7 @@ public final class PipelineConfigBuilder {
     }
 
     public PipelineConfig build() {
-        return new PipelineConfig(argumentName, defaultError, defaultWarning, missingMapper, nullMapper, missingMsg, nullMsg);
-    }
-
-    public void setWasLegacyAsVectorCall() {
-        wasLegacyAsVectorCall = true;
-    }
-
-    public boolean wasLegacyAsVectorCall() {
-        return wasLegacyAsVectorCall;
+        return new PipelineConfig(argumentName, defaultError, defaultWarning, missingMapper, nullMapper, valueForwarding, missingMsg, nullMsg);
     }
 
     void setDefaultError(MessageData defaultError) {
@@ -75,55 +63,9 @@ public final class PipelineConfigBuilder {
         this.defaultWarning = defaultWarning;
     }
 
-    public PipelineConfigBuilder mustNotBeMissing(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
-        missingMapper = null;
-        missingMsg = new MessageData(callObj, errorMsg, msgArgs);
-        return this;
-    }
-
-    public PipelineConfigBuilder mapMissing(Mapper<? super RMissing, ?> mapper) {
-        missingMapper = mapper;
-        missingMsg = null;
-        return this;
-    }
-
-    public PipelineConfigBuilder mapMissing(Mapper<? super RMissing, ?> mapper, RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
-        missingMapper = mapper;
-        missingMsg = new MessageData(callObj, warningMsg, msgArgs);
+    public PipelineConfigBuilder setValueForwarding(boolean flag) {
+        this.valueForwarding = flag;
         return this;
     }
 
-    public PipelineConfigBuilder allowMissing() {
-        return mapMissing(Predef.missingConstant());
-    }
-
-    public PipelineConfigBuilder allowMissing(RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
-        return mapMissing(Predef.missingConstant(), callObj, warningMsg, msgArgs);
-    }
-
-    public PipelineConfigBuilder mustNotBeNull(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
-        nullMapper = null;
-        nullMsg = new MessageData(callObj, errorMsg, msgArgs);
-        return this;
-    }
-
-    public PipelineConfigBuilder mapNull(Mapper<? super RNull, ?> mapper) {
-        nullMapper = mapper;
-        nullMsg = null;
-        return this;
-    }
-
-    public PipelineConfigBuilder mapNull(Mapper<? super RNull, ?> mapper, RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
-        nullMapper = mapper;
-        nullMsg = new MessageData(callObj, warningMsg, msgArgs);
-        return this;
-    }
-
-    public PipelineConfigBuilder allowNull() {
-        return mapNull(Predef.nullConstant());
-    }
-
-    public PipelineConfigBuilder allowNull(RBaseNode callObj, RError.Message warningMsg, Object... msgArgs) {
-        return mapNull(Predef.nullConstant(), callObj, warningMsg, msgArgs);
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java
index d2feefa58d6fc4be0af1cf035d8551df077506f7..8cd3486523dfaf7d8e516ec507601aa45159a7cd 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/PreinitialPhaseBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,9 @@
  */
 package com.oracle.truffle.r.nodes.builtin.casts.fluent;
 
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
+
 import java.util.function.Consumer;
 
 import com.oracle.truffle.r.nodes.builtin.casts.Mapper;
@@ -40,76 +43,76 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * {@link InitialPhaseBuilder} returns that type, so once the user steps outside the configuration,
  * there is no way to invoke configuration related methods defined here.
  */
-public final class PreinitialPhaseBuilder<T> extends InitialPhaseBuilder<T> {
+public final class PreinitialPhaseBuilder extends InitialPhaseBuilder<Object> {
 
-    public PreinitialPhaseBuilder(PipelineBuilder pipelineBuilder) {
+    PreinitialPhaseBuilder(PipelineBuilder pipelineBuilder) {
         super(pipelineBuilder);
     }
 
-    public PreinitialPhaseBuilder<T> conf(Consumer<PipelineConfigBuilder> cfgLambda) {
+    public PreinitialPhaseBuilder conf(Consumer<PipelineConfigBuilder> cfgLambda) {
         cfgLambda.accept(pipelineBuilder().getPipelineConfig());
         return this;
     }
 
-    public InitialPhaseBuilder<T> allowNull() {
-        return conf(c -> c.allowNull());
+    public InitialPhaseBuilder<Object> allowNull() {
+        return returnIf(nullValue());
     }
 
-    public InitialPhaseBuilder<T> mustNotBeNull() {
-        return conf(c -> c.mustNotBeNull(null, null, (Object[]) null));
+    public InitialPhaseBuilder<Object> mustNotBeNull() {
+        return mustBe(nullValue().not());
     }
 
-    public InitialPhaseBuilder<T> mustNotBeNull(RError.Message errorMsg, Object... msgArgs) {
-        return conf(c -> c.mustNotBeNull(null, errorMsg, msgArgs));
+    public InitialPhaseBuilder<Object> mustNotBeNull(RError.Message errorMsg, Object... msgArgs) {
+        return mustBe(nullValue().not(), null, errorMsg, msgArgs);
     }
 
-    public InitialPhaseBuilder<T> mustNotBeNull(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
-        return conf(c -> c.mustNotBeNull(callObj, errorMsg, msgArgs));
+    public InitialPhaseBuilder<Object> mustNotBeNull(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
+        return mustBe(nullValue().not(), callObj, errorMsg, msgArgs);
     }
 
-    public InitialPhaseBuilder<T> mapNull(Mapper<? super RNull, ?> mapper) {
-        return conf(c -> c.mapNull(mapper));
+    public InitialPhaseBuilder<Object> mapNull(Mapper<RNull, ?> mapper) {
+        return mapIf(nullValue(), mapper);
     }
 
-    public InitialPhaseBuilder<T> allowMissing() {
-        return conf(c -> c.allowMissing());
+    public InitialPhaseBuilder<Object> allowMissing() {
+        return returnIf(missingValue());
     }
 
-    public InitialPhaseBuilder<T> mustNotBeMissing() {
-        return conf(c -> c.mustNotBeMissing(null, null, (Object[]) null));
+    public InitialPhaseBuilder<Object> mustNotBeMissing() {
+        return mustBe(missingValue().not());
     }
 
-    public InitialPhaseBuilder<T> mustNotBeMissing(RError.Message errorMsg, Object... msgArgs) {
-        return conf(c -> c.mustNotBeMissing(null, errorMsg, msgArgs));
+    public InitialPhaseBuilder<Object> mustNotBeMissing(RError.Message errorMsg, Object... msgArgs) {
+        return mustBe(missingValue().not(), null, errorMsg, msgArgs);
     }
 
-    public InitialPhaseBuilder<T> mustNotBeMissing(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
-        return conf(c -> c.mustNotBeMissing(callObj, errorMsg, msgArgs));
+    public InitialPhaseBuilder<Object> mustNotBeMissing(RBaseNode callObj, RError.Message errorMsg, Object... msgArgs) {
+        return mustBe(missingValue().not(), callObj, errorMsg, msgArgs);
     }
 
-    public InitialPhaseBuilder<T> mapMissing(Mapper<? super RMissing, ?> mapper) {
-        return conf(c -> c.mapMissing(mapper));
+    public InitialPhaseBuilder<Object> mapMissing(Mapper<RMissing, ?> mapper) {
+        return mapIf(missingValue(), mapper);
     }
 
-    public InitialPhaseBuilder<T> allowNullAndMissing() {
-        return conf(c -> c.allowMissing().allowNull());
+    public InitialPhaseBuilder<Object> allowNullAndMissing() {
+        return returnIf(nullValue().or(missingValue()));
     }
 
     @Override
-    public PreinitialPhaseBuilder<T> defaultError(RBaseNode callObj, RError.Message message, Object... args) {
+    public PreinitialPhaseBuilder defaultError(RBaseNode callObj, RError.Message message, Object... args) {
         pipelineBuilder().getPipelineConfig().setDefaultError(new MessageData(callObj, message, args));
         pipelineBuilder().appendDefaultErrorStep(callObj, message, args);
         return this;
     }
 
     @Override
-    public PreinitialPhaseBuilder<T> defaultError(Message message, Object... args) {
+    public PreinitialPhaseBuilder defaultError(Message message, Object... args) {
         defaultError(null, message, args);
         return this;
     }
 
     @Override
-    public PreinitialPhaseBuilder<T> defaultWarning(RBaseNode callObj, Message message, Object... args) {
+    public PreinitialPhaseBuilder defaultWarning(RBaseNode callObj, Message message, Object... args) {
         pipelineBuilder().getPipelineConfig().setDefaultWarning(new MessageData(callObj, message, args));
         pipelineBuilder().appendDefaultWarningStep(callObj, message, args);
         return this;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java
index 6b94d1cb09259d34657d1f59a872f0919f2b008f..e660d18e3c5dc08dcf48a1edb26d8e763ac58937 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.control;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.source.SourceSection;
@@ -41,7 +42,7 @@ public final class BlockNode extends OperatorNode {
     public static final RNode[] EMPTY_BLOCK = new RNode[0];
 
     @Children protected final RNode[] sequence;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     public BlockNode(SourceSection src, RSyntaxLookup operator, RNode[] sequence) {
         super(src, operator);
@@ -55,7 +56,6 @@ public final class BlockNode extends OperatorNode {
     @Override
     @ExplodeLoop
     public Object execute(VirtualFrame frame) {
-        visibility.execute(frame, true);
         if (sequence.length == 0) {
             return RNull.instance;
         }
@@ -73,6 +73,23 @@ public final class BlockNode extends OperatorNode {
         }
     }
 
+    @Override
+    @ExplodeLoop
+    public Object visibleExecute(VirtualFrame frame) {
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
+        if (sequence.length == 0) {
+            return RNull.instance;
+        }
+        for (int i = 0; i < sequence.length - 1; i++) {
+            sequence[i].voidExecute(frame);
+        }
+        return sequence[sequence.length - 1].visibleExecute(frame);
+    }
+
     @Override
     public RSyntaxNode[] getSyntaxArguments() {
         return RASTUtils.asSyntaxNodes(sequence);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java
index 7d07a30bcd745b778179efbfc0e15bf2febd80b7..51d90997a825da38859ae982d9ed74496041004b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java
@@ -62,9 +62,9 @@ public final class ForNode extends AbstractLoopNode implements RSyntaxNode, RSyn
         String rangeName = AnonymousFrameVariable.create("FOR_RANGE");
         String lengthName = AnonymousFrameVariable.create("FOR_LENGTH");
 
-        this.writeIndexNode = WriteVariableNode.createAnonymous(indexName, null, Mode.REGULAR);
-        this.writeRangeNode = WriteVariableNode.createAnonymous(rangeName, range, Mode.REGULAR);
-        this.writeLengthNode = WriteVariableNode.createAnonymous(lengthName, RLengthNodeGen.create(ReadVariableNode.create(rangeName)), Mode.REGULAR);
+        this.writeIndexNode = WriteVariableNode.createAnonymous(indexName, Mode.REGULAR, null);
+        this.writeRangeNode = WriteVariableNode.createAnonymous(rangeName, Mode.REGULAR, range);
+        this.writeLengthNode = WriteVariableNode.createAnonymous(lengthName, Mode.REGULAR, RLengthNodeGen.create(ReadVariableNode.create(rangeName)));
         this.loopNode = Truffle.getRuntime().createLoopNode(new ForRepeatingNode(this, var.getIdentifier(), body, indexName, lengthName, rangeName));
     }
 
@@ -108,12 +108,12 @@ public final class ForNode extends AbstractLoopNode implements RSyntaxNode, RSyn
 
         ForRepeatingNode(ForNode forNode, String var, RNode body, String indexName, String lengthName, String rangeName) {
             this.forNode = forNode;
-            this.writeElementNode = WriteVariableNode.createAnonymous(var, createIndexedLoad(indexName, rangeName), Mode.REGULAR, false);
+            this.writeElementNode = WriteVariableNode.createAnonymous(var, Mode.REGULAR, createIndexedLoad(indexName, rangeName), false);
             this.body = body;
 
             this.readIndexNode = ReadVariableNode.create(indexName);
             this.readLengthNode = ReadVariableNode.create(lengthName);
-            this.writeIndexNode = WriteVariableNode.createAnonymous(indexName, null, Mode.REGULAR);
+            this.writeIndexNode = WriteVariableNode.createAnonymous(indexName, Mode.REGULAR, null);
             // pre-initialize the profile so that loop exits to not deoptimize
             conditionProfile.profile(false);
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java
index fd5b395b0c86e0fb1294dc8e1eb97ee1b91fcff6..ae9a2cf35dcc7b6299139a3d68d44e23882a4827 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@ public final class IfNode extends OperatorNode {
     @Child private ConvertBooleanNode condition;
     @Child private RNode thenPart;
     @Child private RNode elsePart;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile();
 
@@ -53,30 +53,32 @@ public final class IfNode extends OperatorNode {
         this.elsePart = elsePart == null ? null : elsePart.asRNode();
     }
 
-    /**
-     * Result visibility of an {@code if} expression is not only a property of the {@code if}
-     * builtin; it also depends on whether there is an else branch or not, and on the condition. For
-     * instance, the expression {@code if (FALSE) 23} will evaluate to {@code NULL}, but the result
-     * will not be printed in the shell. Conversely, {@code NULL} will be printed for
-     * {@code if (FALSE) 23 else NULL} because the else branch is given.
-     */
-
-    @Override
-    public Object execute(VirtualFrame frame) {
+    private boolean evaluateCondition(VirtualFrame frame) {
         byte cond = condition.executeByte(frame);
-        visibility.execute(frame, elsePart != null || cond == RRuntime.LOGICAL_TRUE);
-
         if (cond == RRuntime.LOGICAL_NA) {
-            // NA is the only remaining option
             CompilerDirectives.transferToInterpreter();
             throw RError.error(this, RError.Message.NA_UNEXP);
         }
+        assert cond == RRuntime.LOGICAL_FALSE || cond == RRuntime.LOGICAL_TRUE : "logical value none of TRUE|FALSE|NA";
+        return conditionProfile.profile(cond == RRuntime.LOGICAL_TRUE);
+    }
 
-        if (conditionProfile.profile(cond == RRuntime.LOGICAL_TRUE)) {
-            return thenPart.execute(frame);
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        if (evaluateCondition(frame)) {
+            thenPart.voidExecute(frame);
         } else {
-            assert cond == RRuntime.LOGICAL_FALSE : "logical value none of TRUE|FALSE|NA";
+            if (elsePart != null) {
+                elsePart.voidExecute(frame);
+            }
+        }
+    }
 
+    @Override
+    public Object execute(VirtualFrame frame) {
+        if (evaluateCondition(frame)) {
+            return thenPart.execute(frame);
+        } else {
             if (elsePart != null) {
                 return elsePart.execute(frame);
             } else {
@@ -85,6 +87,25 @@ public final class IfNode extends OperatorNode {
         }
     }
 
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
+        if (evaluateCondition(frame)) {
+            return thenPart.visibleExecute(frame);
+        } else {
+            if (elsePart != null) {
+                return elsePart.visibleExecute(frame);
+            } else {
+                // otherwise: return invisible NULL
+                if (visibility == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    visibility = insert(SetVisibilityNode.create());
+                }
+                visibility.execute(frame, false);
+                return RNull.instance;
+            }
+        }
+    }
+
     public ConvertBooleanNode getCondition() {
         return condition;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/RLengthNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/RLengthNode.java
index 14bbeb5c13d9859a7e8421387c9dd5ec6a2e7421..a7a57f523a4f14412abb09f5440eb82abaf47a1a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/RLengthNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/RLengthNode.java
@@ -59,38 +59,32 @@ public abstract class RLengthNode extends RNode {
     }
 
     @Specialization
-    @SuppressWarnings("unused")
-    protected int doNull(RNull operand) {
+    protected int doNull(@SuppressWarnings("unused") RNull operand) {
         return 0;
     }
 
     @Specialization
-    @SuppressWarnings("unused")
-    protected int doLogical(byte operand) {
+    protected int doLogical(@SuppressWarnings("unused") byte operand) {
         return 1;
     }
 
     @Specialization
-    @SuppressWarnings("unused")
-    protected int doInteger(int operand) {
+    protected int doInteger(@SuppressWarnings("unused") int operand) {
         return 1;
     }
 
     @Specialization
-    @SuppressWarnings("unused")
-    protected int doDouble(double operand) {
+    protected int doDouble(@SuppressWarnings("unused") double operand) {
         return 1;
     }
 
     @Specialization
-    @SuppressWarnings("unused")
-    protected int doString(String operand) {
+    protected int doString(@SuppressWarnings("unused") String operand) {
         return 1;
     }
 
     @Specialization
-    @SuppressWarnings("unused")
-    protected int doSymbol(RSymbol operand) {
+    protected int doSymbol(@SuppressWarnings("unused") RSymbol operand) {
         return 1;
     }
 
@@ -101,7 +95,7 @@ public abstract class RLengthNode extends RNode {
         return lengthProfile.profile(cachedClass.cast(operand).getLength());
     }
 
-    @Specialization(contains = "doCachedContainer")
+    @Specialization(replaces = "doCachedContainer")
     protected int doContainer(RAbstractContainer operand,
                     @Cached("create()") VectorLengthProfile lengthProfile) {
         return lengthProfile.profile(operand.getLength());
@@ -142,14 +136,14 @@ public abstract class RLengthNode extends RNode {
     }
 
     @Specialization(guards = "isForeignObject(object)")
-    protected int getForeignSize(VirtualFrame frame, TruffleObject object,
+    protected int getForeignSize(TruffleObject object,
                     @Cached("createHasSize()") Node hasSizeNode,
                     @Cached("createGetSize()") Node getSizeNode) {
         try {
-            if (!(boolean) ForeignAccess.send(hasSizeNode, frame, object)) {
+            if (!(boolean) ForeignAccess.send(hasSizeNode, object)) {
                 return 1;
             }
-            return (int) ForeignAccess.send(getSizeNode, frame, object);
+            return (int) ForeignAccess.send(getSizeNode, object);
         } catch (InteropException e) {
             throw RError.interopError(this, e, object);
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java
index 87aa63e674b51eae64d265e3303944c8e4d1dd35..5eadedf9fbb67ac5f3fe35eb3889ffe541a8d4b9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ import com.oracle.truffle.r.nodes.access.WriteVariableSyntaxNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 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.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -70,28 +71,57 @@ public final class ReplacementDispatchNode extends OperatorNode {
         this.tempNamesStartIndex = tempNamesStartIndex;
     }
 
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        CompilerDirectives.transferToInterpreterAndInvalidate();
+        create(true).voidExecute(frame);
+    }
+
     @Override
     public Object execute(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         return create(false).execute(frame);
+
     }
 
     @Override
-    public void voidExecute(VirtualFrame frame) {
+    public Object visibleExecute(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
-        create(true).voidExecute(frame);
+        return create(false).visibleExecute(frame);
     }
 
     public RNode create(boolean isVoid) {
         RNode replacement;
-        if (lhs.asRSyntaxNode() instanceof RSyntaxCall) {
+        RSyntaxNode lhsSyntax = lhs.asRSyntaxNode();
+        if (lhsSyntax instanceof RSyntaxCall) {
             replacement = createReplacementNode(isVoid);
         } else {
-            replacement = new WriteVariableSyntaxNode(getLazySourceSection(), operator, lhs.asRSyntaxNode(), rhs, isSuper);
+            replacement = createWriteVariableNode(lhsSyntax);
         }
         return replace(replacement);
     }
 
+    private RNode createWriteVariableNode(RSyntaxNode lhsSyntax) {
+        String name;
+        if (lhsSyntax instanceof RSyntaxLookup) {
+            name = ((RSyntaxLookup) lhsSyntax).getIdentifier();
+        } else if (lhsSyntax instanceof RSyntaxConstant) {
+            RSyntaxConstant c = (RSyntaxConstant) lhsSyntax;
+            if (c.getValue() instanceof String) {
+                name = (String) c.getValue();
+            } else {
+                // "this" needs to be initialized for error reporting to work
+                throw RError.error(this, RError.Message.INVALID_LHS, "do_set");
+            }
+        } else {
+            throw RInternalError.unimplemented("unexpected lhs type in replacement: " + lhsSyntax.getClass());
+        }
+        if (name.isEmpty()) {
+            throw RError.error(RError.NO_CALLER, RError.Message.ZERO_LENGTH_VARIABLE);
+        }
+        return new WriteVariableSyntaxNode(getLazySourceSection(), operator, lhsSyntax, name, rhs, isSuper);
+    }
+
     @Override
     public ArgumentsSignature getSyntaxSignature() {
         return ArgumentsSignature.empty(2);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
index 8fea3922499d8129309a55a96d5a685689993d7a..5986bdbb7b83c5648cbb68104b43c0c942287f40 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -174,7 +174,7 @@ abstract class ReplacementNode extends OperatorNode {
             super(source, operator, lhs);
             this.rhs = rhs;
 
-            this.storeRhs = WriteVariableNode.createAnonymous("*rhs*" + tempNamesStartIndex, rhs, WriteVariableNode.Mode.INVISIBLE);
+            this.storeRhs = WriteVariableNode.createAnonymous("*rhs*" + tempNamesStartIndex, WriteVariableNode.Mode.INVISIBLE, rhs);
             this.removeRhs = RemoveAndAnswerNode.create("*rhs*" + tempNamesStartIndex);
         }
 
@@ -368,7 +368,7 @@ abstract class ReplacementNode extends OperatorNode {
             for (int i = calls.size() - 1, tmpIndex = 0; i >= 1; i--, tmpIndex++) {
                 ReadVariableNode newFirstArg = ReadVariableNode.create("*tmp*" + (tempNamesStartIndex + tmpIndex));
                 RNode update = createSpecialFunctionQuery(calls.get(i), newFirstArg, codeBuilderContext);
-                instructions.add(WriteVariableNode.createAnonymous("*tmp*" + (tempNamesStartIndex + tmpIndex + 1), update, WriteVariableNode.Mode.INVISIBLE));
+                instructions.add(WriteVariableNode.createAnonymous("*tmp*" + (tempNamesStartIndex + tmpIndex + 1), WriteVariableNode.Mode.INVISIBLE, update));
             }
             /*
              * Create the update calls, for "a(b(x)) <- z", this would be `a<-` and `b<-`, the
@@ -379,14 +379,14 @@ abstract class ReplacementNode extends OperatorNode {
                 String tmprName = i == 0 ? ("*rhs*" + tempNamesStartIndex) : ("*tmpr*" + (tempNamesStartIndex + i - 1));
                 RNode update = createFunctionUpdate(source, ReadVariableNode.create("*tmp*" + tmpIndex), ReadVariableNode.create(tmprName), calls.get(i), codeBuilderContext);
                 if (i < calls.size() - 1) {
-                    instructions.add(WriteVariableNode.createAnonymous("*tmpr*" + (tempNamesStartIndex + i), update, WriteVariableNode.Mode.INVISIBLE));
+                    instructions.add(WriteVariableNode.createAnonymous("*tmpr*" + (tempNamesStartIndex + i), WriteVariableNode.Mode.INVISIBLE, update));
                 } else {
-                    instructions.add(WriteVariableNode.createAnonymous(targetVarName, update, WriteVariableNode.Mode.REGULAR, isSuper));
+                    instructions.add(WriteVariableNode.createAnonymous(targetVarName, WriteVariableNode.Mode.REGULAR, update, isSuper));
                 }
             }
 
             this.updates = instructions.toArray(new RNode[instructions.size()]);
-            this.targetTmpWrite = WriteVariableNode.createAnonymous(getTargetTmpName(tempNamesStartIndex), target, WriteVariableNode.Mode.INVISIBLE);
+            this.targetTmpWrite = WriteVariableNode.createAnonymous(getTargetTmpName(tempNamesStartIndex), WriteVariableNode.Mode.INVISIBLE, target);
             this.targetTmpRemove = RemoveAndAnswerNode.create(getTargetTmpName(tempNamesStartIndex));
         }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsCharNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsCharNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f60448bc218234d188e7b2b0b017e328c04e7e0
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsCharNode.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+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.r.nodes.unary.CastStringNode;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
+
+@TypeSystemReference(RTypesFlatLayout.class)
+public abstract class AsCharNode extends FFIUpCallNode.Arg1 {
+    private static final CharSXPWrapper CharSXPWrapper_NA = CharSXPWrapper.create(RRuntime.STRING_NA);
+
+    public abstract CharSXPWrapper execute(Object obj);
+
+    @Specialization
+    protected CharSXPWrapper asChar(CharSXPWrapper obj) {
+        return obj;
+    }
+
+    @Specialization
+    protected CharSXPWrapper asChar(RAbstractStringVector obj) {
+        if (obj.getLength() == 0) {
+            return CharSXPWrapper_NA;
+        } else {
+            return CharSXPWrapper.create(obj.getDataAt(0));
+        }
+    }
+
+    @Specialization
+    protected CharSXPWrapper asChar(RSymbol obj) {
+        return CharSXPWrapper.create(obj.getName());
+    }
+
+    @Specialization(guards = "obj.getLength() > 0")
+    protected CharSXPWrapper asChar(RAbstractAtomicVector obj, //
+                    @Cached("createNonPreserving()") CastStringNode castStringNode) {
+        Object castObj = castStringNode.executeString(obj);
+        if (castObj instanceof String) {
+            return CharSXPWrapper.create((String) castObj);
+        } else if (castObj instanceof RAbstractStringVector) {
+            return CharSXPWrapper.create(((RAbstractStringVector) castObj).getDataAt(0));
+        } else {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Fallback
+    protected CharSXPWrapper asCharFallback(@SuppressWarnings("unused") Object obj) {
+        return CharSXPWrapper_NA;
+    }
+
+    public static AsCharNode create() {
+        return AsCharNodeGen.create();
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsIntegerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsIntegerNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9cc0ef6bb481f6ea2e3e56148f86b71b03f123c
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsIntegerNode.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+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.r.nodes.unary.CastIntegerNode;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+
+/**
+ * Implements the {@code Rf_asInteger} GNU R function . The behavior is subtly different (more
+ * permissive error-wise) that {@link CastIntegerNode}. Non-castable values return {@code NA}.
+ */
+@TypeSystemReference(RTypesFlatLayout.class)
+public abstract class AsIntegerNode extends FFIUpCallNode.Arg1 {
+
+    public abstract int execute(Object obj);
+
+    @Specialization
+    protected int asInteger(int obj) {
+        return obj;
+    }
+
+    @Specialization
+    protected int asInteger(double obj) {
+        return (int) obj;
+    }
+
+    @Specialization
+    protected int asReal(RAbstractDoubleVector obj) {
+        if (obj.getLength() == 0) {
+            return RRuntime.INT_NA;
+        }
+        return (int) obj.getDataAt(0);
+    }
+
+    @Specialization
+    protected int asReal(RAbstractIntVector obj) {
+        if (obj.getLength() == 0) {
+            return RRuntime.INT_NA;
+        }
+        return obj.getDataAt(0);
+    }
+
+    @Specialization(guards = "obj.getLength() > 0")
+    protected int asReal(RAbstractAtomicVector obj,
+                    @Cached("createNonPreserving()") CastIntegerNode castIntegerNode) {
+        Object castObj = castIntegerNode.executeInt(obj);
+        if (castObj instanceof Integer) {
+            return (Integer) castObj;
+        } else if (castObj instanceof RAbstractIntVector) {
+            return ((RAbstractIntVector) castObj).getDataAt(0);
+        } else {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Fallback
+    protected int asRealFallback(@SuppressWarnings("unused") Object obj) {
+        return RRuntime.INT_NA;
+    }
+
+    public static AsIntegerNode create() {
+        return AsIntegerNodeGen.create();
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsLogicalNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..b56d55b6e4a4d86cd99ffd88bdb5d93f003aad76
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsLogicalNode.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+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.r.nodes.unary.CastLogicalNode;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+
+@TypeSystemReference(RTypesFlatLayout.class)
+public abstract class AsLogicalNode extends FFIUpCallNode.Arg1 {
+
+    public abstract int execute(Object obj);
+
+    @Specialization
+    protected int asLogical(byte b) {
+        return b;
+    }
+
+    @Specialization
+    protected int asLogical(RAbstractLogicalVector obj) {
+        if (obj.getLength() == 0) {
+            return RRuntime.INT_NA;
+        }
+        return obj.getDataAt(0);
+    }
+
+    @Specialization(guards = "obj.getLength() > 0")
+    protected int asLogical(RAbstractAtomicVector obj,
+                    @Cached("createNonPreserving()") CastLogicalNode castLogicalNode) {
+        Object castObj = castLogicalNode.execute(obj);
+        if (castObj instanceof Byte) {
+            return (byte) castObj;
+        } else if (castObj instanceof RAbstractLogicalVector) {
+            return ((RAbstractLogicalVector) castObj).getDataAt(0);
+        } else {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Fallback
+    protected int asLogicalFallback(@SuppressWarnings("unused") Object obj) {
+        return RRuntime.INT_NA;
+    }
+
+    public static AsLogicalNode create() {
+        return AsLogicalNodeGen.create();
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsRealNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsRealNode.java
index cfca08ce67c7e0a3170bbd9f667709baf99665ab..0f977902306076282c0a669aa56fdbe7ee609505 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsRealNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/AsRealNode.java
@@ -12,37 +12,35 @@
  */
 package com.oracle.truffle.r.nodes.ffi;
 
+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.nodes.Node;
+import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
 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.data.model.RAbstractVector;
 
 /**
  * Implements the {@code Rf_asReal} GNU R function (which is also used internally). The behavior is
  * subtly different (more permissive error-wise) that {@link CastDoubleNode}. Non-castable values
  * return {@code NA}.
  */
-public abstract class AsRealNode extends Node {
-    @Child private CastDoubleNode castDoubleNode = CastDoubleNode.createNonPreserving();
+@TypeSystemReference(RTypesFlatLayout.class)
+public abstract class AsRealNode extends FFIUpCallNode.Arg1 {
 
     public abstract double execute(Object obj);
 
     @Specialization
-    protected double asReal(Double obj) {
+    protected double asReal(double obj) {
         return obj;
     }
 
     @Specialization
-    protected double asReal(Integer obj) {
+    protected double asReal(int obj) {
         return obj;
     }
 
@@ -62,13 +60,14 @@ public abstract class AsRealNode extends Node {
         return obj.getDataAt(0);
     }
 
-    @Specialization(guards = "isVectorAtomic(obj)")
-    protected double asReal(Object obj) {
+    @Specialization(guards = "obj.getLength() > 0")
+    protected double asReal(RAbstractAtomicVector obj,
+                    @Cached("createNonPreserving()") CastDoubleNode castDoubleNode) {
         Object castObj = castDoubleNode.executeDouble(obj);
         if (castObj instanceof Double) {
             return (double) castObj;
-        } else if (castObj instanceof RDoubleVector) {
-            return ((RDoubleVector) castObj).getDataAt(0);
+        } else if (castObj instanceof RAbstractDoubleVector) {
+            return ((RAbstractDoubleVector) castObj).getDataAt(0);
         } else {
             throw RInternalError.shouldNotReachHere();
         }
@@ -79,16 +78,7 @@ public abstract class AsRealNode extends Node {
         return RRuntime.DOUBLE_NA;
     }
 
-    public static boolean isVectorAtomic(Object obj) {
-        return obj instanceof Byte || obj instanceof String || isNonScalarVectorAtomic(obj);
-    }
-
-    private static boolean isNonScalarVectorAtomic(Object obj) {
-        if (obj instanceof RAbstractLogicalVector || obj instanceof RAbstractStringVector || obj instanceof RAbstractComplexVector) {
-            RAbstractVector avec = (RAbstractVector) obj;
-            return avec.getLength() >= 1;
-        } else {
-            return false;
-        }
+    public static AsRealNode create() {
+        return AsRealNodeGen.create();
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/CoerceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/CoerceVectorNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7eb9d97d31188cc0fc7981ed94022e038561645
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/CoerceVectorNode.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.unimplemented;
+
+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.r.nodes.unary.CastComplexNode;
+import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
+import com.oracle.truffle.r.nodes.unary.CastExpressionNode;
+import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
+import com.oracle.truffle.r.nodes.unary.CastListNode;
+import com.oracle.truffle.r.nodes.unary.CastLogicalNode;
+import com.oracle.truffle.r.nodes.unary.CastNode;
+import com.oracle.truffle.r.nodes.unary.CastRawNode;
+import com.oracle.truffle.r.nodes.unary.CastStringNode;
+import com.oracle.truffle.r.nodes.unary.CastSymbolNode;
+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.data.RList;
+import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
+
+/**
+ * Implements Rf_coerceVector.
+ */
+public abstract class CoerceVectorNode extends FFIUpCallNode.Arg2 {
+
+    public static CoerceVectorNode create() {
+        return CoerceVectorNodeGen.create();
+    }
+
+    @Specialization(guards = "value.isS4()")
+    Object doS4Object(RTypedValue value, int mode) {
+        throw RError.nyi(RError.NO_CALLER, "Rf_coerceVector for S4 objects.");
+    }
+
+    // Note: caches should cover all valid possibilities
+    @Specialization(guards = {"!isS4Object(value)", "isNotList(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99")
+    Object doCached(Object value, int mode,
+                    @Cached("mode") int cachedMode,
+                    @Cached("createCastNode(cachedMode)") CastNode castNode) {
+        return castNode.execute(value);
+    }
+
+    // Lists are coerced with only preserved names unlike other types
+    @Specialization(guards = {"!isS4Object(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99")
+    Object doCached(RList value, int mode,
+                    @Cached("mode") int cachedMode,
+                    @Cached("createCastNodeForList(cachedMode)") CastNode castNode) {
+        return castNode.execute(value);
+    }
+
+    @Fallback
+    @TruffleBoundary
+    Object doFallback(Object value, Object mode) {
+        String type = value != null ? value.getClass().getSimpleName() : "null";
+        throw unimplemented(String.format("Rf_coerceVector unimplemented for type %s or mode %s.", type, mode));
+    }
+
+    static boolean isS4Object(Object obj) {
+        return obj instanceof RTypedValue && ((RTypedValue) obj).isS4();
+    }
+
+    static boolean isNotList(Object obj) {
+        return !(obj instanceof RList);
+    }
+
+    static boolean isValidMode(int mode) {
+        return mode >= SEXPTYPE.NILSXP.code && mode <= SEXPTYPE.RAWSXP.code;
+    }
+
+    static CastNode createCastNode(int mode) {
+        return createCastNode(mode, false);
+    }
+
+    static CastNode createCastNodeForList(int mode) {
+        return createCastNode(mode, true);
+    }
+
+    private static CastNode createCastNode(int mode, boolean forList) {
+        SEXPTYPE type = SEXPTYPE.mapInt(mode);
+        boolean preserveDims = !forList;
+        boolean preserveAttrs = !forList;
+        switch (type) {
+            case SYMSXP:
+                return CastSymbolNode.createForRFFI(false, false, false);
+            case NILSXP:
+                return new CastNullNode();
+            case LISTSXP:
+                throw unimplemented("Rf_coerceVector called with unimplemented for PairLists.");
+            case LANGSXP:
+                throw unimplemented("Rf_coerceVector called with unimplemented for RLanguage.");
+            case ENVSXP:
+                return new EnvironmentCast();
+            case VECSXP:
+                return CastListNode.createForRFFI(true, forList, forList);
+            case EXPRSXP:
+                return CastExpressionNode.createForRFFI(false, false, false);
+            case INTSXP:
+                return CastIntegerNode.createForRFFI(true, preserveDims, preserveAttrs);
+            case REALSXP:
+                return CastDoubleNode.createForRFFI(true, preserveDims, preserveAttrs);
+            case LGLSXP:
+                return CastLogicalNode.createForRFFI(true, preserveDims, preserveAttrs);
+            case STRSXP:
+                return CastStringNode.createForRFFI(true, preserveDims, preserveAttrs);
+            case CPLXSXP:
+                return CastComplexNode.createForRFFI(true, preserveDims, preserveAttrs);
+            case RAWSXP:
+                return CastRawNode.createForRFFI(true, preserveDims, preserveAttrs);
+            default:
+                throw unimplemented(String.format("Rf_coerceVector called with unimplemented mode %d (type %s).", mode, type));
+        }
+    }
+
+    private static final class CastNullNode extends CastNode {
+        @Override
+        @TruffleBoundary
+        public Object execute(@SuppressWarnings("unused") Object value) {
+            if (value instanceof RList) {
+                throw RError.error(RError.NO_CALLER, Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, "list", "coerceVectorList");
+            } else {
+                throw RError.error(RError.NO_CALLER, Message.CANNOT_COERCE, getTypeName(value), "NULL");
+            }
+        }
+
+        private static String getTypeName(Object val) {
+            Object value = RRuntime.asAbstractVector(val);
+            if (value == null) {
+                return "null";
+            }
+            return value instanceof RTypedValue ? ((RTypedValue) value).getRType().getName() : value.getClass().getSimpleName();
+        }
+    }
+
+    private static final class EnvironmentCast extends CastNode {
+        @Override
+        @TruffleBoundary
+        public Object execute(Object value) {
+            throw RError.error(RError.NO_CALLER, Message.ENVIRONMENTS_COERCE);
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..7cf4549706518f3fc9c496a10f11bcc125c9d9c2
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+import com.oracle.truffle.api.nodes.Node;
+
+public abstract class FFIUpCallNode extends Node {
+    protected abstract int numArgs();
+
+    public abstract static class Arg0 extends FFIUpCallNode {
+        public abstract Object executeObject();
+
+        @Override
+        protected int numArgs() {
+            return 0;
+        }
+
+    }
+
+    public abstract static class Arg1 extends FFIUpCallNode {
+        public abstract Object executeObject(Object arg0);
+
+        @Override
+        protected int numArgs() {
+            return 1;
+        }
+    }
+
+    public abstract static class Arg2 extends FFIUpCallNode {
+        public abstract Object executeObject(Object arg0, Object arg1);
+
+        @Override
+        protected int numArgs() {
+            return 2;
+        }
+    }
+
+    public abstract static class Arg3 extends FFIUpCallNode {
+        public abstract Object executeObject(Object arg0, Object arg1, Object arg2);
+
+        @Override
+        protected int numArgs() {
+            return 3;
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7d26f933bccbd58fc565b82df14d3dd87b84c0d
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/FFIUpCallRootNode.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+import java.util.function.Supplier;
+
+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.nodes.ffi.ListAccessNodesFactory.CADDRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CADRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CARNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDDRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.ListAccessNodesFactory.CDRNodeGen;
+import com.oracle.truffle.r.nodes.ffi.MiscNodesFactory.LENGTHNodeGen;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.context.RContext;
+
+public final class FFIUpCallRootNode extends RootNode {
+    private static final RootCallTarget[] rootCallTargets = new RootCallTarget[RFFIUpCallMethod.values().length];
+
+    @Child private FFIUpCallNode theFFIUpCallNode;
+    private final int numArgs;
+
+    private FFIUpCallRootNode(FFIUpCallNode child) {
+        super(RContext.getRRuntimeASTAccess().getTruffleRLanguage(), null, new FrameDescriptor());
+        theFFIUpCallNode = child;
+        this.numArgs = child.numArgs();
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        Object[] args = frame.getArguments();
+        switch (numArgs) {
+            case 0:
+                return ((FFIUpCallNode.Arg0) theFFIUpCallNode).executeObject();
+            case 1:
+                return ((FFIUpCallNode.Arg1) theFFIUpCallNode).executeObject(args[0]);
+            case 2:
+                return ((FFIUpCallNode.Arg2) theFFIUpCallNode).executeObject(args[0], args[1]);
+            case 3:
+                return ((FFIUpCallNode.Arg3) theFFIUpCallNode).executeObject(args[0], args[1], args[2]);
+            default:
+                throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    static void add(RFFIUpCallMethod upCallMethod, Supplier<FFIUpCallNode> constructor) {
+
+        FFIUpCallRootNode rootNode = new FFIUpCallRootNode(constructor.get());
+        rootCallTargets[upCallMethod.ordinal()] = Truffle.getRuntime().createCallTarget(rootNode);
+    }
+
+    public static RootCallTarget getCallTarget(RFFIUpCallMethod upCallMethod) {
+        RootCallTarget target = rootCallTargets[upCallMethod.ordinal()];
+        assert target != null;
+        return target;
+    }
+
+    static void register() {
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asReal, AsRealNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asLogical, AsLogicalNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asInteger, AsIntegerNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_asChar, AsCharNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.Rf_coerceVector, CoerceVectorNode::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CAR, CARNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CDR, CDRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CADR, CADRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CADDR, CADDRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.CDDR, CDDRNodeGen::create);
+        FFIUpCallRootNode.add(RFFIUpCallMethod.LENGTH, LENGTHNodeGen::create);
+    }
+
+}
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
similarity index 70%
rename from com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java
rename to com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
index 498519f4837e28824ff4fa6d9fc840e2c3636967..a12d923fd9d1eac96a6a53f5fe799a458d3abb74 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
@@ -20,7 +20,11 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.runtime.ffi;
+package com.oracle.truffle.r.nodes.ffi;
+
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.guarantee;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.guaranteeInstanceOf;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.unimplemented;
 
 import java.nio.charset.StandardCharsets;
 import java.util.function.Function;
@@ -28,9 +32,12 @@ 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.frame.MaterializedFrame;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.nodes.RASTUtils;
+import com.oracle.truffle.r.nodes.ffi.ParseResult.ParseStatus;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RCleanUp;
@@ -72,24 +79,24 @@ import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RUnboundValue;
-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.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 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.CharSXPWrapper;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.ffi.ParseResult.ParseStatus;
-import com.oracle.truffle.r.runtime.ffi.jni.TraceUpCallsAdapter;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
 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.nodes.RSyntaxNode;
 import com.oracle.truffle.r.runtime.rng.RRNG;
 
 /**
- * This class provides a simple Java-based implementation of {@link UpCallsRFFI}, using no Truffle
- * mechanisms.
+ * This class provides a simple Java-based implementation of {@link UpCallsRFFI}, where all the
+ * argument values are standarde Java types, i.e. no special types used by Truffle NFI or Truffle
+ * LLVM.
  *
  * 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,185 +105,75 @@ 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 JavaUpCallsRFFI implements UpCallsRFFI {
-
-    private TraceUpCallsAdapter tracer;
-
-    public JavaUpCallsRFFI() {
-        if (RFFIUtils.traceEnabled()) {
-            tracer = new TraceUpCallsAdapter();
-        }
-    }
-
-    private static RuntimeException unimplemented() {
-        return unimplemented("");
-    }
-
-    private static RuntimeException unimplemented(String message) {
-        System.err.println(message);
-        try {
-            throw RInternalError.unimplemented(message);
-        } catch (Error e) {
-            e.printStackTrace();
-            try {
-                Thread.sleep(100000);
-            } catch (InterruptedException e2) {
-                e2.printStackTrace();
-            }
-            throw e;
-        }
-    }
-
-    private static void guarantee(boolean condition) {
-        guarantee(condition, "");
-    }
-
-    private static void guarantee(boolean condition, String message) {
-        if (!condition) {
-            unimplemented(message);
-        }
-    }
-
-    public static <T> T guaranteeInstanceOf(Object x, Class<T> clazz) {
-        if (x == null) {
-            guarantee(false, "unexpected type: null instead of " + clazz.getSimpleName());
-        } else if (!clazz.isInstance(x)) {
-            guarantee(false, "unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of " + clazz.getSimpleName());
-        }
-        return clazz.cast(x);
-    }
+public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
 
     // Checkstyle: stop method name check
 
     @Override
     public RIntVector Rf_ScalarInteger(int value) {
-        if (tracer != null) {
-            tracer.Rf_ScalarInteger(value);
-        }
         return RDataFactory.createIntVectorFromScalar(value);
     }
 
     @Override
     public RLogicalVector Rf_ScalarLogical(int value) {
-        if (tracer != null) {
-            tracer.Rf_ScalarLogical(value);
+        byte byteValue;
+        if (value == RRuntime.INT_NA) {
+            byteValue = RRuntime.LOGICAL_NA;
+        } else {
+            byteValue = (byte) (value & 0xFF);
         }
-        return RDataFactory.createLogicalVectorFromScalar(value != 0);
+        return RDataFactory.createLogicalVectorFromScalar(byteValue);
     }
 
     @Override
     public RDoubleVector Rf_ScalarDouble(double value) {
-        if (tracer != null) {
-            tracer.Rf_ScalarDouble(value);
-        }
         return RDataFactory.createDoubleVectorFromScalar(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());
     }
 
     @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) {
-            return ((Integer) x).intValue();
-        } else if (x instanceof Double) {
-            return RRuntime.double2int((Double) x);
-        } else if (x instanceof Byte) {
-            return RRuntime.logical2int((Byte) x);
-        } else if (x instanceof RLogicalVector) {
-            return RRuntime.logical2int(((RLogicalVector) x).getDataAt(0));
-        } else {
-            guaranteeInstanceOf(x, RIntVector.class);
-            return ((RIntVector) x).getDataAt(0);
-        }
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asInteger).call(x);
     }
 
     @Override
     public double Rf_asReal(Object x) {
-        if (tracer != null) {
-            tracer.Rf_asReal(x);
-        }
-        if (x instanceof Double) {
-            return ((Double) x).doubleValue();
-        } else if (x instanceof Byte) {
-            return RRuntime.logical2double((Byte) x);
-        } else {
-            guaranteeInstanceOf(x, RDoubleVector.class);
-            return ((RDoubleVector) x).getDataAt(0);
-        }
+        return (double) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asReal).call(x);
     }
 
     @Override
     public int Rf_asLogical(Object x) {
-        if (tracer != null) {
-            tracer.Rf_asLogical(x);
-        }
-        if (x instanceof Byte) {
-            return ((Byte) x).intValue();
-        } else {
-            guaranteeInstanceOf(x, RLogicalVector.class);
-            return ((RLogicalVector) x).getDataAt(0);
-        }
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asLogical).call(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 CharSXPWrapper.create(((RSymbol) x).getName());
-        }
-
-        Object obj = RRuntime.asAbstractVector(x);
-        if (obj instanceof RAbstractVector) {
-            RAbstractVector vector = (RAbstractVector) obj;
-            if (vector.getLength() > 0) {
-                if (vector instanceof RAbstractStringVector) {
-                    return CharSXPWrapper.create(((RAbstractStringVector) vector).getDataAt(0));
-                } else {
-                    unimplemented("asChar type " + x.getClass());
-                }
-            }
-        }
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_asChar).call(x);
+    }
 
-        return CharSXPWrapper.create(RRuntime.STRING_NA);
+    @Override
+    public Object Rf_coerceVector(Object x, int mode) {
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.Rf_coerceVector).call(x, mode);
     }
 
     @Override
-    public Object Rf_mkCharLenCE(byte[] bytes, int encoding) {
-        if (tracer != null) {
-            tracer.Rf_mkCharLenCE(bytes, encoding);
-        }
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
         // TODO: handle encoding properly
-        return CharSXPWrapper.create(new String(bytes, StandardCharsets.UTF_8));
+        return CharSXPWrapper.create(new String((byte[]) bytes, StandardCharsets.UTF_8));
     }
 
     @Override
     public Object Rf_cons(Object car, Object cdr) {
-        if (tracer != null) {
-            tracer.Rf_cons(car, cdr);
-        }
         return RDataFactory.createPairList(car, cdr);
     }
 
     @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;
         try {
@@ -287,10 +184,7 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
     }
 
     @Override
-    public Object R_do_MAKE_CLASS(String clazz) {
-        if (tracer != null) {
-            tracer.R_do_MAKE_CLASS(clazz);
-        }
+    public Object R_do_MAKE_CLASS(Object 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);
@@ -298,25 +192,16 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object Rf_findVar(Object symbolArg, Object envArg) {
-        if (tracer != null) {
-            tracer.Rf_findVar(symbolArg, envArg);
-        }
         return findVarInFrameHelper(envArg, symbolArg, true);
     }
 
     @Override
     public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
-        if (tracer != null) {
-            tracer.Rf_findVarInFrame(envArg, symbolArg);
-        }
         return findVarInFrameHelper(envArg, symbolArg, false);
     }
 
     @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
         return findVarInFrameHelper(envArg, symbolArg, false);
@@ -347,9 +232,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
             RAttributable attrObj = (RAttributable) obj;
@@ -368,9 +250,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
     @Override
     @TruffleBoundary
     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;
             String nameAsString;
@@ -420,10 +299,7 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
     }
 
     @Override
-    public int Rf_inherits(Object x, String clazz) {
-        if (tracer != null) {
-            tracer.Rf_inherits(x, clazz);
-        }
+    public int Rf_inherits(Object x, Object clazz) {
         int result = 0;
         RStringVector hierarchy = getClassHr(x);
         for (int i = 0; i < hierarchy.getLength(); i++) {
@@ -435,43 +311,28 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
     }
 
     @Override
-    public Object Rf_install(String name) {
-        if (tracer != null) {
-            tracer.Rf_install(name);
-        }
-        return RDataFactory.createSymbolInterned(name);
+    public Object Rf_install(Object name) {
+        return RDataFactory.createSymbolInterned((String) name);
     }
 
     @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);
     }
 
     @Override
     public int Rf_isString(Object x) {
-        if (tracer != null) {
-            tracer.Rf_isString(x);
-        }
         return RRuntime.checkType(x, RType.Character) ? 1 : 0;
     }
 
     @Override
     public int Rf_isNull(Object x) {
-        if (tracer != null) {
-            tracer.Rf_isNull(x);
-        }
         return x == RNull.instance ? 1 : 0;
     }
 
     @Override
     public Object Rf_PairToVectorList(Object x) {
-        if (tracer != null) {
-            tracer.Rf_PairToVectorList(x);
-        }
         if (x == RNull.instance) {
             return RDataFactory.createList();
         }
@@ -480,34 +341,22 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
     }
 
     @Override
-    public void Rf_error(String msg) {
-        if (tracer != null) {
-            tracer.Rf_error(msg);
-        }
+    public void Rf_error(Object msg) {
         throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
     @Override
-    public void Rf_warning(String msg) {
-        if (tracer != null) {
-            tracer.Rf_warning(msg);
-        }
+    public void Rf_warning(Object msg) {
         RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, msg);
     }
 
     @Override
-    public void Rf_warningcall(Object call, String msg) {
-        if (tracer != null) {
-            tracer.Rf_warningcall(call, msg);
-        }
-        RErrorHandling.warningcallRFFI(call, msg);
+    public void Rf_warningcall(Object call, Object msg) {
+        RErrorHandling.warningcallRFFI(call, (String) msg);
     }
 
     @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) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED);
@@ -537,9 +386,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object Rf_allocateArray(int mode, Object dimsObj) {
-        if (tracer != null) {
-            tracer.Rf_allocateArray(mode, dimsObj);
-        }
         RIntVector dims = (RIntVector) dimsObj;
         int n = 1;
         int[] newDims = new int[dims.getLength()];
@@ -561,9 +407,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
             throw RError.error(RError.SHOW_CALLER2, RError.Message.NEGATIVE_EXTENTS_TO_MATRIX);
@@ -588,43 +431,21 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public int Rf_nrows(Object x) {
-        if (tracer != null) {
-            tracer.Rf_nrows(x);
-        }
         return RRuntime.nrows(x);
     }
 
     @Override
     public int Rf_ncols(Object x) {
-        if (tracer != null) {
-            tracer.Rf_ncols(x);
-        }
         return RRuntime.ncols(x);
     }
 
     @Override
     public int LENGTH(Object x) {
-        if (tracer != null) {
-            tracer.LENGTH(x);
-        }
-        if (x instanceof RAbstractContainer) {
-            return ((RAbstractContainer) x).getLength();
-        } else if (x == RNull.instance) {
-            return 0;
-        } else if (x instanceof CharSXPWrapper) {
-            return ((CharSXPWrapper) x).getContents().length();
-        } else if (x instanceof Integer || x instanceof Double || x instanceof Byte || x instanceof String) {
-            return 1;
-        } else {
-            throw unimplemented("unexpected value: " + x);
-        }
+        return (int) FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.LENGTH).call(x);
     }
 
     @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());
@@ -632,18 +453,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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);
     }
 
     @Override
     public Object RAW(Object x) {
-        if (tracer != null) {
-            tracer.RAW(x);
-        }
         if (x instanceof RRawVector) {
             return ((RRawVector) x).getDataWithoutCopying();
         } else if (x instanceof RRaw) {
@@ -655,9 +470,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object LOGICAL(Object x) {
-        if (tracer != null) {
-            tracer.LOGICAL(x);
-        }
         if (x instanceof RLogicalVector) {
             return ((RLogicalVector) x).getDataWithoutCopying();
         } else if (x instanceof Byte) {
@@ -669,9 +481,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object INTEGER(Object x) {
-        if (tracer != null) {
-            tracer.INTEGER(x);
-        }
         if (x instanceof RIntVector) {
             return ((RIntVector) x).getDataWithoutCopying();
         } else if (x instanceof RIntSequence) {
@@ -693,9 +502,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object REAL(Object x) {
-        if (tracer != null) {
-            tracer.REAL(x);
-        }
         if (x instanceof RDoubleVector) {
             return ((RDoubleVector) x).getDataWithoutCopying();
         } else if (x instanceof RDoubleSequence) {
@@ -708,18 +514,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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 CharSXPWrapper.create(vector.getDataAt(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) {
             return ((RExpression) vec).getDataAt(i);
@@ -730,9 +530,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public int NAMED(Object x) {
-        if (tracer != null) {
-            tracer.NAMED(x);
-        }
         if (x instanceof RShareable) {
             return ((RShareable) x).isShared() ? 1 : 0;
         } else {
@@ -742,9 +539,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
             return RLanguage.fromList(x, RLanguage.RepType.CALL);
@@ -755,9 +549,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public int TYPEOF(Object x) {
-        if (tracer != null) {
-            tracer.TYPEOF(x);
-        }
         if (x instanceof CharSXPWrapper) {
             return SEXPTYPE.CHARSXP.code;
         } else {
@@ -768,9 +559,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
     @Override
     @TruffleBoundary
     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;
         } else {
@@ -780,9 +568,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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 RSequence || x instanceof RExternalPtr,
                         "unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of RShareable or RExternalPtr");
@@ -797,9 +582,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
             return 0;
@@ -810,18 +592,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object PRINTNAME(Object x) {
-        if (tracer != null) {
-            tracer.PRINTNAME(x);
-        }
         guaranteeInstanceOf(x, RSymbol.class);
         return CharSXPWrapper.create(((RSymbol) x).getName());
     }
 
     @Override
     public Object TAG(Object e) {
-        if (tracer != null) {
-            tracer.TAG(e);
-        }
         if (e instanceof RPairList) {
             return ((RPairList) e).getTag();
         } else {
@@ -833,78 +609,31 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
-            return ((RPairList) e).car();
-        } else {
-            return ((RLanguage) e).getDataAtAsObject(0);
-        }
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CAR).call(e);
     }
 
     @Override
     public Object CDR(Object e) {
-        if (tracer != null) {
-            tracer.CDR(e);
-        }
-        if (e instanceof RLanguage) {
-            RLanguage lang = (RLanguage) e;
-            RPairList l = lang.getPairList();
-            return l.cdr();
-        } else {
-            guaranteeInstanceOf(e, RPairList.class);
-            return ((RPairList) e).cdr();
-        }
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CDR).call(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) {
-            return ((RPairList) e).cadr();
-        } else {
-            return ((RLanguage) e).getDataAtAsObject(1);
-        }
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CADR).call(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) {
-            return ((RPairList) e).caddr();
-        } else {
-            return ((RLanguage) e).getDataAtAsObject(2);
-        }
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CADDR).call(e);
     }
 
     @Override
     public Object CDDR(Object e) {
-        if (tracer != null) {
-            tracer.CDDR(e);
-        }
-        if (e instanceof RLanguage) {
-            RLanguage lang = (RLanguage) e;
-            RPairList l = lang.getPairList();
-            return l.cddr();
-        } else {
-            guaranteeInstanceOf(e, RPairList.class);
-            return ((RPairList) e).cddr();
-        }
+        return FFIUpCallRootNode.getCallTarget(RFFIUpCallMethod.CDDR).call(e);
     }
 
     @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);
         } else {
@@ -917,9 +646,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
@@ -927,9 +653,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
@@ -937,18 +660,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object SETCADR(Object x, Object y) {
-        if (tracer != null) {
-            tracer.SETCADR(x, y);
-        }
         SETCAR(CDR(x), y);
         return y;
     }
 
     @Override
     public Object SYMVALUE(Object x) {
-        if (tracer != null) {
-            tracer.SYMVALUE(x);
-        }
         if (!(x instanceof RSymbol)) {
             throw RInternalError.shouldNotReachHere();
         }
@@ -962,9 +679,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public void SET_SYMVALUE(Object x, Object v) {
-        if (tracer != null) {
-            tracer.SET_SYMVALUE(x, v);
-        }
         if (!(x instanceof RSymbol)) {
             throw RInternalError.shouldNotReachHere();
         }
@@ -973,9 +687,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
@@ -983,18 +694,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
     }
 
     @Override
     public Object Rf_eval(Object expr, Object env) {
-        if (tracer != null) {
-            tracer.Rf_eval(expr, env);
-        }
         guarantee(env instanceof REnvironment);
         Object result;
         if (expr instanceof RPromise) {
@@ -1023,9 +728,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
         guarantee(symbolObj instanceof RSymbol);
@@ -1042,9 +744,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
@@ -1052,9 +751,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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();
         guarantee(rho == baseEnv);
@@ -1067,9 +763,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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);
             DynamicObject attributes = ((RAttributable) from).getAttributes();
@@ -1080,9 +773,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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))),
                         RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0))));
@@ -1091,25 +781,16 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public void Rf_copyListMatrix(Object s, Object t, int byrow) {
-        if (tracer != null) {
-            tracer.Rf_copyListMatrix(s, t, byrow);
-        }
         throw unimplemented();
     }
 
     @Override
     public void Rf_copyMatrix(Object s, Object t, int byrow) {
-        if (tracer != null) {
-            tracer.Rf_copyMatrix(s, t, byrow);
-        }
         throw unimplemented();
     }
 
     @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();
         try {
@@ -1131,26 +812,11 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
      */
     @Override
     public Object R_ToplevelExec() {
-        if (tracer != null) {
-            tracer.R_ToplevelExec();
-        }
         return RErrorHandling.resetAndGetHandlerStacks();
     }
 
-    /**
-     * Helper function for {@code R_TopLevelExec}, see {@link #R_ToplevelExec()}, called after C
-     * function returns.
-     */
-    public void R_ToplevelExecRestoreErrorHandlerStacks(Object stacks) {
-        RErrorHandling.HandlerStacks handlerStacks = guaranteeInstanceOf(stacks, RErrorHandling.HandlerStacks.class);
-        RErrorHandling.restoreHandlerStacks(handlerStacks);
-    }
-
     @Override
     public int RDEBUG(Object x) {
-        if (tracer != null) {
-            tracer.RDEBUG(x);
-        }
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         if (env instanceof REnvironment.Function) {
             REnvironment.Function funcEnv = (REnvironment.Function) env;
@@ -1163,9 +829,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
             REnvironment.Function funcEnv = (REnvironment.Function) env;
@@ -1180,9 +843,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public int RSTEP(Object x) {
-        if (tracer != null) {
-            tracer.RSTEP(x);
-        }
         @SuppressWarnings("unused")
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         throw RInternalError.unimplemented("RSTEP");
@@ -1190,9 +850,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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");
@@ -1200,9 +857,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object ENCLOS(Object x) {
-        if (tracer != null) {
-            tracer.ENCLOS(x);
-        }
         REnvironment env = guaranteeInstanceOf(x, REnvironment.class);
         Object result = env.getParent();
         if (result == null) {
@@ -1213,18 +867,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
     }
 
     @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;
         assert srcFile == RNull.instance;
@@ -1243,9 +891,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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;
         REnvironment env = guaranteeInstanceOf(envArg, REnvironment.class);
@@ -1254,25 +899,16 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public String R_HomeDir() {
-        if (tracer != null) {
-            tracer.R_HomeDir();
-        }
         return REnvVars.rHome();
     }
 
     @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);
     }
 
     @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) {
@@ -1287,81 +923,51 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object R_GlobalEnv() {
-        if (tracer != null) {
-            tracer.R_GlobalEnv();
-        }
         return RContext.getInstance().stateREnvironment.getGlobalEnv();
     }
 
     @Override
     public Object R_BaseEnv() {
-        if (tracer != null) {
-            tracer.R_BaseEnv();
-        }
         return RContext.getInstance().stateREnvironment.getBaseEnv();
     }
 
     @Override
     public Object R_BaseNamespace() {
-        if (tracer != null) {
-            tracer.R_BaseNamespace();
-        }
         return RContext.getInstance().stateREnvironment.getBaseNamespace();
     }
 
     @Override
     public Object R_NamespaceRegistry() {
-        if (tracer != null) {
-            tracer.R_NamespaceRegistry();
-        }
         return RContext.getInstance().stateREnvironment.getNamespaceRegistry();
     }
 
     @Override
-    public int isInteractive() {
-        if (tracer != null) {
-            tracer.isInteractive();
-        }
+    public int R_Interactive() {
         return RContext.getInstance().isInteractive() ? 1 : 0;
     }
 
     @Override
-    public int isS4Object(Object x) {
-        if (tracer != null) {
-            tracer.isS4Object(x);
-        }
+    public int IS_S4_OBJECT(Object x) {
         return x instanceof RS4Object ? 1 : 0;
     }
 
     @Override
-    public void Rprintf(String message) {
-        if (tracer != null) {
-            tracer.Rprintf(message);
-        }
-        RContext.getInstance().getConsoleHandler().print(message);
+    public void Rprintf(Object message) {
+        RContext.getInstance().getConsoleHandler().print((String) message);
     }
 
     @Override
     public void GetRNGstate() {
-        if (tracer != null) {
-            tracer.GetRNGstate();
-        }
         RRNG.getRNGState();
     }
 
     @Override
     public void PutRNGstate() {
-        if (tracer != null) {
-            tracer.PutRNGstate();
-        }
         RRNG.putRNGState();
     }
 
     @Override
     public double unif_rand() {
-        if (tracer != null) {
-            tracer.unif_rand();
-        }
         return RRNG.unifRand();
     }
 
@@ -1369,9 +975,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
@@ -1389,9 +992,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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) {
@@ -1406,9 +1006,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object R_getContextEnv(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextEnv(c);
-        }
         RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
         if (rCaller == RCaller.topLevel) {
             return RContext.getInstance().stateREnvironment.getGlobalEnv();
@@ -1435,9 +1032,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object R_getContextFun(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextFun(c);
-        }
         RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
         if (rCaller == RCaller.topLevel) {
             return RNull.instance;
@@ -1464,9 +1058,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object R_getContextCall(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextCall(c);
-        }
         RCaller rCaller = guaranteeInstanceOf(c, RCaller.class);
         if (rCaller == RCaller.topLevel) {
             return RNull.instance;
@@ -1476,9 +1067,6 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public Object R_getContextSrcRef(Object c) {
-        if (tracer != null) {
-            tracer.R_getContextSrcRef(c);
-        }
         Object o = R_getContextFun(c);
         if (!(o instanceof RFunction)) {
             return RNull.instance;
@@ -1493,17 +1081,11 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public int R_insideBrowser() {
-        if (tracer != null) {
-            tracer.R_insideBrowser();
-        }
         return RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser() ? 1 : 0;
     }
 
     @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;
@@ -1511,18 +1093,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @Override
     public int R_isEqual(Object x, Object y) {
-        if (tracer != null) {
-            tracer.R_isEqual(x, y);
-        }
         return x == y ? 1 : 0;
     }
 
     @Override
     @TruffleBoundary
     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;
@@ -1530,94 +1106,77 @@ public class JavaUpCallsRFFI implements UpCallsRFFI {
 
     @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);
     }
 
     @Override
     public long R_ExternalPtrAddr(Object x) {
-        if (tracer != null) {
-            tracer.R_ExternalPtrAddr(x);
-        }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         return p.getAddr().asAddress();
     }
 
     @Override
     public Object R_ExternalPtrTag(Object x) {
-        if (tracer != null) {
-            tracer.R_ExternalPtrTag(x);
-        }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         return p.getTag();
     }
 
     @Override
     public Object R_ExternalPtrProt(Object x) {
-        if (tracer != null) {
-            tracer.R_ExternalPtrProt(x);
-        }
         RExternalPtr p = guaranteeInstanceOf(x, RExternalPtr.class);
         return p.getProt();
     }
 
     @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));
     }
 
     @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);
     }
 
     @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);
     }
 
     @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);
+    public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) {
+        REnvironment env = RDataFactory.createNewEnv(REnvironment.UNNAMED, true, initialSize);
         RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
         return env;
     }
 
-    // Implementation specific support
+    @Override
+    public int PRSEEN(Object x) {
+        RPromise promise = RFFIUtils.guaranteeInstanceOf(x, RPromise.class);
+        return promise.getGPBits();
+    }
+
+    @Override
+    public Object PRENV(Object x) {
+        RPromise promise = RFFIUtils.guaranteeInstanceOf(x, RPromise.class);
+        final MaterializedFrame frame = promise.getFrame();
+        return frame != null ? REnvironment.frameToEnvironment(frame) : RNull.instance;
+    }
 
-    /**
-     * 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);
-        }
+    @Override
+    public Object R_PromiseExpr(Object x) {
+        // R_PromiseExpr usually checks, if 'x' is a byte code object. This is not possible in
+        // FastR, so simply call PRCODE.
+        return PRCODE(x);
     }
 
-    /**
-     * 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());
+    @Override
+    public Object PRCODE(Object x) {
+        RPromise promise = RFFIUtils.guaranteeInstanceOf(x, RPromise.class);
+        RSyntaxNode expr = RASTUtils.unwrap(promise.getRep()).asRSyntaxNode();
+        return RASTUtils.createLanguageElement(expr);
     }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/ListAccessNodes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/ListAccessNodes.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b443987e44dea159fc884aef156d3318affecdc
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/ListAccessNodes.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.unimplemented;
+
+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.r.runtime.data.RLanguage;
+import com.oracle.truffle.r.runtime.data.RPairList;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
+
+/**
+ * Nodes that implement {@code CAR}, {@code CDR}, etc. N.B. GNU R does not error check the
+ * arguments; it will crash (segv) if given, say, a numeric arg.
+ */
+public final class ListAccessNodes {
+
+    @TypeSystemReference(RTypesFlatLayout.class)
+    public abstract static class CARNode extends FFIUpCallNode.Arg1 {
+        @Specialization
+        protected Object car(RPairList pl) {
+            return pl.car();
+        }
+
+        @Specialization
+        protected Object car(RLanguage lang) {
+            return lang.getDataAtAsObject(0);
+        }
+
+        @Fallback
+        protected Object car(@SuppressWarnings("unused") Object obj) {
+            throw unimplemented("CAR only works on pair lists and language objects");
+        }
+
+    }
+
+    @TypeSystemReference(RTypesFlatLayout.class)
+    public abstract static class CDRNode extends FFIUpCallNode.Arg1 {
+        @Specialization
+        protected Object cdr(RPairList pl) {
+            return pl.cdr();
+        }
+
+        @Specialization
+        protected Object cdr(RLanguage lang) {
+            RPairList l = lang.getPairList();
+            return l.cdr();
+        }
+
+        @Fallback
+        protected Object cdr(@SuppressWarnings("unused") Object obj) {
+            throw unimplemented("CDR only works on pair lists and language objects");
+
+        }
+    }
+
+    @TypeSystemReference(RTypesFlatLayout.class)
+    public abstract static class CADRNode extends FFIUpCallNode.Arg1 {
+        @Specialization
+        protected Object cadr(RPairList pl) {
+            return pl.cadr();
+        }
+
+        @Specialization
+        protected Object cadr(RLanguage lang) {
+            return lang.getDataAtAsObject(1);
+        }
+
+        @Fallback
+        protected Object cadr(@SuppressWarnings("unused") Object obj) {
+            throw unimplemented("CADR only works on pair lists and language objects");
+        }
+
+    }
+
+    @TypeSystemReference(RTypesFlatLayout.class)
+    public abstract static class CADDRNode extends FFIUpCallNode.Arg1 {
+        @Specialization
+        protected Object caddr(RPairList pl) {
+            return pl.caddr();
+        }
+
+        @Specialization
+        protected Object caddr(RLanguage lang) {
+            return lang.getDataAtAsObject(2);
+        }
+
+        @Fallback
+        protected Object caddr(@SuppressWarnings("unused") Object obj) {
+            throw unimplemented("CADDR only works on pair lists and language objects");
+        }
+
+    }
+
+    @TypeSystemReference(RTypesFlatLayout.class)
+    public abstract static class CDDRNode extends FFIUpCallNode.Arg1 {
+        @Specialization
+        protected Object cddr(RPairList pl) {
+            return pl.cddr();
+        }
+
+        @Specialization
+        protected Object cdr(RLanguage lang) {
+            RPairList l = lang.getPairList();
+            return l.cddr();
+        }
+
+        @Fallback
+        protected Object cddr(@SuppressWarnings("unused") Object obj) {
+            throw unimplemented("CDDR only works on pair lists and language objects");
+
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/MiscNodes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/MiscNodes.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d833e1641f64b7dc1614d2792ff47265f4cacee
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/MiscNodes.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+import com.oracle.truffle.api.CompilerDirectives;
+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.r.runtime.RError;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
+import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
+
+public final class MiscNodes {
+
+    @TypeSystemReference(RTypesFlatLayout.class)
+    public abstract static class LENGTHNode extends FFIUpCallNode.Arg1 {
+
+        @Specialization
+        protected int length(@SuppressWarnings("unused") RNull obj) {
+            return 0;
+        }
+
+        @Specialization
+        protected int length(@SuppressWarnings("unused") int x) {
+            return 1;
+        }
+
+        @Specialization
+        protected int length(@SuppressWarnings("unused") double x) {
+            return 1;
+        }
+
+        @Specialization
+        protected int length(@SuppressWarnings("unused") byte x) {
+            return 1;
+        }
+
+        @Specialization
+        protected int length(@SuppressWarnings("unused") String x) {
+            return 1;
+        }
+
+        @Specialization
+        protected int length(CharSXPWrapper obj) {
+            return obj.getContents().length();
+        }
+
+        @Specialization
+        protected int length(RAbstractContainer obj) {
+            // Should this use RLengthNode?
+            return obj.getLength();
+        }
+
+        @Fallback
+        protected int length(Object obj) {
+            CompilerDirectives.transferToInterpreter();
+            throw RError.error(RError.SHOW_CALLER2, RError.Message.LENGTH_MISAPPLIED, SEXPTYPE.gnuRTypeForObject(obj).name());
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ParseResult.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/ParseResult.java
similarity index 90%
rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ParseResult.java
rename to com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/ParseResult.java
index d4c71e01bd9db7b54b821bdeec2afda8ea9589b6..1a5dc11242769558430a273c3f16dc61f598b8bb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ParseResult.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/ParseResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,7 +20,9 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.runtime.ffi;
+package com.oracle.truffle.r.nodes.ffi;
+
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
 
 /**
  * Used in implementation of {@link UpCallsRFFI#R_ParseVector(Object, int, Object)}.
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..a998220115fb7fa4aec65f56d40e8c6087f704ce
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.ffi;
+
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+
+/**
+ * Generated from {@link UpCallsRFFI}. Any native code that is dependent on the ordinal value of
+ * these enums must be kept in sync. The {@link #main} method will generate the appropriate C
+ * #define statements.
+ */
+public enum RFFIUpCallMethod {
+    CADDR("(object) : object"),
+    CADR("(object) : object"),
+    CAR("(object) : object"),
+    CDDR("(object) : object"),
+    CDR("(object) : object"),
+    DUPLICATE_ATTRIB("(object, object) : void"),
+    ENCLOS("(object) : object"),
+    GetRNGstate("() : void"),
+    INTEGER("(object) : object"),
+    IS_S4_OBJECT("(object) : sint32"),
+    LENGTH("(object) : sint32"),
+    LOGICAL("(object) : object"),
+    NAMED("(object) : sint32"),
+    OBJECT("(object) : sint32"),
+    PRCODE("(object) : object"),
+    PRENV("(object) : object"),
+    PRINTNAME("(object) : object"),
+    PRSEEN("(object) : sint32"),
+    PRVALUE("(object) : object"),
+    PutRNGstate("() : void"),
+    RAW("(object) : object"),
+    RDEBUG("(object) : sint32"),
+    REAL("(object) : object"),
+    RSTEP("(object) : sint32"),
+    R_BaseEnv("() : object"),
+    R_BaseNamespace("() : object"),
+    R_BindingIsLocked("(object, object) : sint32"),
+    R_CHAR("(object) : object"),
+    R_CleanUp("(sint32, sint32, sint32) : void"),
+    R_ExternalPtrAddr("(object) : object"),
+    R_ExternalPtrProt("(object) : object"),
+    R_ExternalPtrTag("(object) : object"),
+    R_FindNamespace("(object) : object"),
+    R_GlobalContext("() : object"),
+    R_GlobalEnv("() : object"),
+    R_HomeDir("() : object"),
+    R_Interactive("() : sint32"),
+    R_MakeExternalPtr("(object, object, object) : object"),
+    R_NamespaceRegistry("() : object"),
+    R_NewHashedEnv("(object, sint32) : object"),
+    R_ParseVector("(object, sint32, object) : object"),
+    R_PromiseExpr("(object) : object"),
+    R_SetExternalPtrAddr("(object, object) : void"),
+    R_SetExternalPtrProt("(object, object) : void"),
+    R_SetExternalPtrTag("(object, object) : void"),
+    R_ToplevelExec("() : object"),
+    R_computeIdentical("(object, object, sint32) : sint32"),
+    R_do_MAKE_CLASS("(pointer) : object"),
+    R_getContextCall("(object) : object"),
+    R_getContextEnv("(object) : object"),
+    R_getContextFun("(object) : object"),
+    R_getContextSrcRef("(object) : object"),
+    R_getGlobalFunctionContext("() : object"),
+    R_getParentFunctionContext("(object) : object"),
+    R_insideBrowser("() : sint32"),
+    R_isEqual("(object, object) : sint32"),
+    R_isGlobal("(object) : sint32"),
+    R_lsInternal3("(object, sint32, sint32) : object"),
+    R_tryEval("(object, object, object) : object"),
+    Rf_GetOption1("(object) : object"),
+    Rf_PairToVectorList("(object) : object"),
+    Rf_ScalarDouble("(double) : object"),
+    Rf_ScalarInteger("(sint32) : object"),
+    Rf_ScalarLogical("(sint32) : object"),
+    Rf_ScalarString("(object) : object"),
+    Rf_allocateArray("(sint32, object) : object"),
+    Rf_allocateMatrix("(sint32, sint32, sint32) : object"),
+    Rf_allocateVector("(sint32, sint32) : object"),
+    Rf_anyDuplicated("(object, sint32) : sint32"),
+    Rf_asChar("(object) : object"),
+    Rf_asInteger("(object) : sint32"),
+    Rf_asLogical("(object) : sint32"),
+    Rf_asReal("(object) : double"),
+    Rf_classgets("(object, object) : object"),
+    Rf_coerceVector("(object, sint32) : object"),
+    Rf_cons("(object, object) : object"),
+    Rf_copyListMatrix("(object, object, sint32) : void"),
+    Rf_copyMatrix("(object, object, sint32) : void"),
+    Rf_defineVar("(object, object, object) : void"),
+    Rf_duplicate("(object, sint32) : object"),
+    Rf_error("(pointer) : void"),
+    Rf_eval("(object, object) : object"),
+    Rf_findVar("(object, object) : object"),
+    Rf_findVarInFrame("(object, object) : object"),
+    Rf_findVarInFrame3("(object, object, sint32) : object"),
+    Rf_findfun("(object, object) : object"),
+    Rf_getAttrib("(object, object) : object"),
+    Rf_gsetVar("(object, object, object) : void"),
+    Rf_inherits("(pointer, object) : sint32"),
+    Rf_install("(pointer) : object"),
+    Rf_isNull("(object) : sint32"),
+    Rf_isString("(object) : sint32"),
+    Rf_lengthgets("(object, sint32) : object"),
+    Rf_mkCharLenCE("(pointer, sint32, sint32) : object"),
+    Rf_ncols("(object) : sint32"),
+    Rf_nrows("(object) : sint32"),
+    Rf_setAttrib("(object, object, object) : void"),
+    Rf_warning("(pointer) : void"),
+    Rf_warningcall("(object, pointer) : void"),
+    Rprintf("(pointer) : void"),
+    SETCADR("(object, object) : object"),
+    SETCAR("(object, object) : object"),
+    SETCDR("(object, object) : object"),
+    SET_RDEBUG("(object, sint32) : void"),
+    SET_RSTEP("(object, sint32) : void"),
+    SET_STRING_ELT("(object, sint32, object) : void"),
+    SET_SYMVALUE("(object, object) : void"),
+    SET_TAG("(object, object) : object"),
+    SET_TYPEOF_FASTR("(object, sint32) : object"),
+    SET_VECTOR_ELT("(object, sint32, object) : void"),
+    STRING_ELT("(object, sint32) : object"),
+    SYMVALUE("(object) : object"),
+    TAG("(object) : object"),
+    TYPEOF("(object) : sint32"),
+    VECTOR_ELT("(object, sint32) : object"),
+    unif_rand("() : double");
+
+    /**
+     * The signature used for the upcall in Truffle NFI.
+     */
+    public final String nfiSignature;
+
+    RFFIUpCallMethod(String signature) {
+        this.nfiSignature = signature;
+    }
+
+    public static void main(String[] args) {
+        for (RFFIUpCallMethod f : RFFIUpCallMethod.values()) {
+            System.out.printf("#define %s_x %d\n", f.name(), f.ordinal());
+        }
+    }
+
+}
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUtils.java
similarity index 77%
rename from com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
rename to com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUtils.java
index fa21f16be67c76d37887a304de50831c867f8f4d..9b7df136add07eda78a75719536b4af2007874fd 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/RFFIUtils.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUtils.java
@@ -20,7 +20,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.runtime.ffi;
+package com.oracle.truffle.r.nodes.ffi;
 
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
@@ -29,10 +29,12 @@ import java.nio.file.Path;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.FastROptions;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
 
 /**
  * Mostly support for tracing R FFI up/down calls. Currently tracing of the arguments to calls is
@@ -45,7 +47,6 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
  *
  */
 public class RFFIUtils {
-    private static boolean initialized;
     /**
      * Set this to {@code true} when it is not possible to set {@link FastROptions}.
      */
@@ -65,16 +66,24 @@ public class RFFIUtils {
      */
     private static int depth;
 
-    public static void initialize() {
-        if (!initialized) {
-            traceEnabled = alwaysTrace || FastROptions.TraceNativeCalls.getBooleanValue();
-            if (traceEnabled) {
-                if (traceStream == null) {
-                    initTraceStream();
-                }
+    /**
+     * Handles the initialization of the RFFI downcalls/upcall implementation.
+     *
+     * @param upCallsRFFIImpl the concrete, implementation-specific variant of {@link UpCallsRFFI}.
+     * @return if tracing is enabled an instance of {@link TracingUpCallsRFFIImpl} that wraps
+     *         {@code upCallsRFFIImpl} else {@code upCallsRFFIImpl}.
+     */
+    public static UpCallsRFFI initialize(UpCallsRFFI upCallsRFFIImpl) {
+        UpCallsRFFI returnUpCallsRFFIImpl = upCallsRFFIImpl;
+        traceEnabled = alwaysTrace || FastROptions.TraceNativeCalls.getBooleanValue();
+        if (traceEnabled) {
+            if (traceStream == null) {
+                initTraceStream();
             }
-            initialized = true;
+            returnUpCallsRFFIImpl = new TracingUpCallsRFFIImpl(upCallsRFFIImpl);
         }
+        FFIUpCallRootNode.register();
+        return returnUpCallsRFFIImpl;
     }
 
     private static void initTraceStream() {
@@ -140,7 +149,6 @@ public class RFFIUtils {
     }
 
     private static void traceCall(CallMode mode, String name, int depthValue, Object... args) {
-        assert initialized;
         if (traceEnabled) {
             StringBuffer sb = new StringBuffer();
             sb.append("CallRFFI[");
@@ -181,6 +189,34 @@ public class RFFIUtils {
         }
     }
 
+    // Error handling
+    static RuntimeException unimplemented() {
+        return unimplemented("");
+    }
+
+    static RuntimeException unimplemented(String message) {
+        throw RInternalError.unimplemented(message);
+    }
+
+    static void guarantee(boolean condition) {
+        guarantee(condition, "");
+    }
+
+    static void guarantee(boolean condition, String message) {
+        if (!condition) {
+            unimplemented(message);
+        }
+    }
+
+    public static <T> T guaranteeInstanceOf(Object x, Class<T> clazz) {
+        if (x == null) {
+            guarantee(false, "unexpected type: null instead of " + clazz.getSimpleName());
+        } else if (!clazz.isInstance(x)) {
+            guarantee(false, "unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of " + clazz.getSimpleName());
+        }
+        return clazz.cast(x);
+    }
+
     // Miscellaneous support functions
 
     public static byte[] wrapChar(char v) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd78becb64849ad60a065a0da30db451b4d4ad15
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.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;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+
+final class TracingUpCallsRFFIImpl implements UpCallsRFFI {
+    // Checkstyle: stop method name check
+
+    private final UpCallsRFFI delegate;
+
+    public TracingUpCallsRFFIImpl(UpCallsRFFI delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public RIntVector Rf_ScalarInteger(int value) {
+        RFFIUtils.traceUpCall("Rf_ScalarInteger", value);
+        return delegate.Rf_ScalarInteger(value);
+    }
+
+    @Override
+    public RLogicalVector Rf_ScalarLogical(int value) {
+        RFFIUtils.traceUpCall("Rf_ScalarLogical", value);
+        return delegate.Rf_ScalarLogical(value);
+    }
+
+    @Override
+    public RDoubleVector Rf_ScalarDouble(double value) {
+        RFFIUtils.traceUpCall("Rf_ScalarDouble", value);
+        return delegate.Rf_ScalarDouble(value);
+    }
+
+    @Override
+    public RStringVector Rf_ScalarString(Object value) {
+        RFFIUtils.traceUpCall("Rf_ScalarString", value);
+        return delegate.Rf_ScalarString(value);
+    }
+
+    @Override
+    public int Rf_asInteger(Object x) {
+        RFFIUtils.traceUpCall("Rf_asInteger", x);
+        return delegate.Rf_asInteger(x);
+    }
+
+    @Override
+    public double Rf_asReal(Object x) {
+        RFFIUtils.traceUpCall("Rf_asReal", x);
+        return delegate.Rf_asReal(x);
+    }
+
+    @Override
+    public int Rf_asLogical(Object x) {
+        RFFIUtils.traceUpCall("Rf_asLogical", x);
+        return delegate.Rf_asLogical(x);
+    }
+
+    @Override
+    public Object Rf_asChar(Object x) {
+        RFFIUtils.traceUpCall("Rf_asChar", x);
+        return delegate.Rf_asChar(x);
+    }
+
+    @Override
+    public Object Rf_coerceVector(Object x, int mode) {
+        RFFIUtils.traceUpCall("Rf_coerceVector", x, mode);
+        return delegate.Rf_coerceVector(x, mode);
+    }
+
+    @Override
+    public Object Rf_mkCharLenCE(Object bytes, int len, int encoding) {
+        RFFIUtils.traceUpCall("Rf_mkCharLenCE", bytes);
+        return delegate.Rf_mkCharLenCE(bytes, len, encoding);
+    }
+
+    @Override
+    public Object Rf_cons(Object car, Object cdr) {
+        RFFIUtils.traceUpCall("Rf_cons", car, cdr);
+        return delegate.Rf_cons(car, cdr);
+    }
+
+    @Override
+    public void Rf_defineVar(Object symbolArg, Object value, Object envArg) {
+        RFFIUtils.traceUpCall("Rf_defineVar", symbolArg, value, envArg);
+        delegate.Rf_defineVar(symbolArg, value, envArg);
+    }
+
+    @Override
+    public Object R_do_MAKE_CLASS(Object clazz) {
+        RFFIUtils.traceUpCall("R_do_MAKE_CLASS", clazz);
+        return delegate.R_do_MAKE_CLASS(clazz);
+    }
+
+    @Override
+    public Object Rf_findVar(Object symbolArg, Object envArg) {
+        RFFIUtils.traceUpCall("Rf_findVar", symbolArg, envArg);
+        return delegate.Rf_findVar(symbolArg, envArg);
+    }
+
+    @Override
+    public Object Rf_findVarInFrame(Object envArg, Object symbolArg) {
+        RFFIUtils.traceUpCall("Rf_findVarInFrame", envArg, symbolArg);
+        return delegate.Rf_findVarInFrame(envArg, symbolArg);
+    }
+
+    @Override
+    public Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet) {
+        RFFIUtils.traceUpCall("Rf_findVarInFrame3", envArg, symbolArg);
+        return delegate.Rf_findVarInFrame3(envArg, symbolArg, doGet);
+    }
+
+    @Override
+    public Object Rf_getAttrib(Object obj, Object name) {
+        RFFIUtils.traceUpCall("Rf_getAttrib", obj, name);
+        return delegate.Rf_getAttrib(obj, name);
+    }
+
+    @Override
+    public void Rf_setAttrib(Object obj, Object name, Object val) {
+        RFFIUtils.traceUpCall("Rf_setAttrib", obj, name, val);
+        delegate.Rf_setAttrib(obj, name, val);
+    }
+
+    @Override
+    public int Rf_inherits(Object x, Object clazz) {
+        RFFIUtils.traceUpCall("Rf_inherits", x, clazz);
+        return delegate.Rf_inherits(x, clazz);
+    }
+
+    @Override
+    public Object Rf_install(Object name) {
+        RFFIUtils.traceUpCall("Rf_install", name);
+        return delegate.Rf_install(name);
+    }
+
+    @Override
+    public Object Rf_lengthgets(Object x, int newSize) {
+        RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize);
+        return delegate.Rf_lengthgets(x, newSize);
+    }
+
+    @Override
+    public int Rf_isString(Object x) {
+        RFFIUtils.traceUpCall("Rf_isString", x);
+        return delegate.Rf_isString(x);
+    }
+
+    @Override
+    public int Rf_isNull(Object x) {
+        RFFIUtils.traceUpCall("Rf_isNull", x);
+        return delegate.Rf_isNull(x);
+    }
+
+    @Override
+    public Object Rf_PairToVectorList(Object x) {
+        RFFIUtils.traceUpCall("Rf_PairToVectorList", x);
+        return delegate.Rf_PairToVectorList(x);
+    }
+
+    @Override
+    public void Rf_error(Object msg) {
+        RFFIUtils.traceUpCall("Rf_error", msg);
+        delegate.Rf_error(msg);
+    }
+
+    @Override
+    public void Rf_warning(Object msg) {
+        RFFIUtils.traceUpCall("Rf_warning", msg);
+        delegate.Rf_warning(msg);
+    }
+
+    @Override
+    public void Rf_warningcall(Object call, Object msg) {
+        RFFIUtils.traceUpCall("Rf_warningcall", call, msg);
+        delegate.Rf_warningcall(call, msg);
+    }
+
+    @Override
+    public Object Rf_allocateVector(int mode, int n) {
+        RFFIUtils.traceUpCall("Rf_allocateVector", mode, n);
+        return delegate.Rf_allocateVector(mode, n);
+    }
+
+    @Override
+    public Object Rf_allocateArray(int mode, Object dimsObj) {
+        RFFIUtils.traceUpCall("Rf_allocateArray", mode, dimsObj);
+        return null;
+    }
+
+    @Override
+    public Object Rf_allocateMatrix(int mode, int nrow, int ncol) {
+        RFFIUtils.traceUpCall("Rf_allocateMatrix", mode, ncol, nrow);
+        return delegate.Rf_allocateMatrix(mode, nrow, ncol);
+    }
+
+    @Override
+    public int Rf_nrows(Object x) {
+        RFFIUtils.traceUpCall("Rf_nrows", x);
+        return delegate.Rf_nrows(x);
+    }
+
+    @Override
+    public int Rf_ncols(Object x) {
+        RFFIUtils.traceUpCall("Rf_ncols", x);
+        return delegate.Rf_ncols(x);
+    }
+
+    @Override
+    public int LENGTH(Object x) {
+        RFFIUtils.traceUpCall("LENGTH", x);
+        return delegate.LENGTH(x);
+    }
+
+    @Override
+    public void SET_STRING_ELT(Object x, int i, Object v) {
+        RFFIUtils.traceUpCall("SET_STRING_ELT", x, i, v);
+        delegate.SET_STRING_ELT(x, i, v);
+    }
+
+    @Override
+    public void SET_VECTOR_ELT(Object x, int i, Object v) {
+        RFFIUtils.traceUpCall("SET_VECTOR_ELT", i, v);
+        delegate.SET_VECTOR_ELT(x, i, v);
+    }
+
+    @Override
+    public Object RAW(Object x) {
+        RFFIUtils.traceUpCall("RAW", x);
+        return delegate.RAW(x);
+    }
+
+    @Override
+    public Object LOGICAL(Object x) {
+        RFFIUtils.traceUpCall("LOGICAL", x);
+        return delegate.LOGICAL(x);
+    }
+
+    @Override
+    public Object INTEGER(Object x) {
+        RFFIUtils.traceUpCall("INTEGER", x);
+        return delegate.INTEGER(x);
+    }
+
+    @Override
+    public Object REAL(Object x) {
+        RFFIUtils.traceUpCall("REAL", x);
+        return delegate.REAL(x);
+    }
+
+    @Override
+    public Object STRING_ELT(Object x, int i) {
+        RFFIUtils.traceUpCall("STRING_ELT", x, i);
+        return delegate.STRING_ELT(x, i);
+    }
+
+    @Override
+    public Object VECTOR_ELT(Object x, int i) {
+        RFFIUtils.traceUpCall("VECTOR_ELT", x, i);
+        return delegate.VECTOR_ELT(x, i);
+    }
+
+    @Override
+    public int NAMED(Object x) {
+        RFFIUtils.traceUpCall("NAMED", x);
+        return delegate.NAMED(x);
+    }
+
+    @Override
+    public Object SET_TYPEOF_FASTR(Object x, int v) {
+        RFFIUtils.traceUpCall("SET_TYPEOF_FASTR", x, v);
+        return delegate.SET_TYPEOF_FASTR(x, v);
+    }
+
+    @Override
+    public int TYPEOF(Object x) {
+        RFFIUtils.traceUpCall("TYPEOF", x);
+        return delegate.TYPEOF(x);
+    }
+
+    @Override
+    public int OBJECT(Object x) {
+        RFFIUtils.traceUpCall("OBJECT", x);
+        return delegate.OBJECT(x);
+    }
+
+    @Override
+    public Object Rf_duplicate(Object x, int deep) {
+        RFFIUtils.traceUpCall("Rf_duplicate", x, deep);
+        return delegate.Rf_duplicate(x, deep);
+    }
+
+    @Override
+    public int Rf_anyDuplicated(Object x, int fromLast) {
+        RFFIUtils.traceUpCall("Rf_anyDuplicated", x, fromLast);
+        return delegate.Rf_anyDuplicated(x, fromLast);
+    }
+
+    @Override
+    public Object PRINTNAME(Object x) {
+        RFFIUtils.traceUpCall("PRINTNAME", x);
+        return delegate.PRINTNAME(x);
+    }
+
+    @Override
+    public Object TAG(Object e) {
+        RFFIUtils.traceUpCall("TAG", e);
+        return delegate.TAG(e);
+    }
+
+    @Override
+    public Object CAR(Object e) {
+        RFFIUtils.traceUpCall("CAR", e);
+        return delegate.CAR(e);
+    }
+
+    @Override
+    public Object CDR(Object e) {
+        RFFIUtils.traceUpCall("CDR", e);
+        return delegate.CDR(e);
+    }
+
+    @Override
+    public Object CADR(Object e) {
+        RFFIUtils.traceUpCall("CADR", e);
+        return delegate.CADR(e);
+    }
+
+    @Override
+    public Object CADDR(Object e) {
+        RFFIUtils.traceUpCall("CADDR", e);
+        return delegate.CADDR(e);
+    }
+
+    @Override
+    public Object CDDR(Object e) {
+        RFFIUtils.traceUpCall("CDDR", e);
+        return delegate.CDDR(e);
+    }
+
+    @Override
+    public Object SET_TAG(Object x, Object y) {
+        RFFIUtils.traceUpCall("SET_TAG", x, y);
+        return delegate.SET_TAG(x, y);
+    }
+
+    @Override
+    public Object SETCAR(Object x, Object y) {
+        RFFIUtils.traceUpCall("SETCAR", x, y);
+        return delegate.SETCAR(x, y);
+    }
+
+    @Override
+    public Object SETCDR(Object x, Object y) {
+        RFFIUtils.traceUpCall("SETCDR", x, y);
+        return delegate.SETCDR(x, y);
+    }
+
+    @Override
+    public Object SETCADR(Object x, Object y) {
+        RFFIUtils.traceUpCall("SETCADR", x);
+        return delegate.SETCADR(x, y);
+    }
+
+    @Override
+    public Object SYMVALUE(Object x) {
+        RFFIUtils.traceUpCall("SYMVALUE", x);
+        return delegate.SYMVALUE(x);
+    }
+
+    @Override
+    public void SET_SYMVALUE(Object x, Object v) {
+        RFFIUtils.traceUpCall("SET_SYMVALUE", x, v);
+        delegate.SET_SYMVALUE(x, v);
+    }
+
+    @Override
+    public int R_BindingIsLocked(Object sym, Object env) {
+        RFFIUtils.traceUpCall("R_BindingIsLocked", sym, env);
+        return delegate.R_BindingIsLocked(sym, env);
+    }
+
+    @Override
+    public Object R_FindNamespace(Object name) {
+        RFFIUtils.traceUpCall("R_FindNamespace", name);
+        return delegate.R_FindNamespace(name);
+    }
+
+    @Override
+    public Object Rf_eval(Object expr, Object env) {
+        RFFIUtils.traceUpCall("Rf_eval", expr, env);
+        return delegate.Rf_eval(expr, env);
+    }
+
+    @Override
+    public Object Rf_findfun(Object symbolObj, Object envObj) {
+        RFFIUtils.traceUpCall("Rf_findfun", symbolObj, envObj);
+        return delegate.Rf_findfun(symbolObj, envObj);
+    }
+
+    @Override
+    public Object Rf_GetOption1(Object tag) {
+        RFFIUtils.traceUpCall("Rf_GetOption1", tag);
+        return delegate.Rf_GetOption1(tag);
+    }
+
+    @Override
+    public void Rf_gsetVar(Object symbol, Object value, Object rho) {
+        RFFIUtils.traceUpCall("Rf_gsetVar", symbol, value, rho);
+        delegate.Rf_gsetVar(symbol, value, rho);
+    }
+
+    @Override
+    public void DUPLICATE_ATTRIB(Object to, Object from) {
+        RFFIUtils.traceUpCall("DUPLICATE_ATTRIB", to, from);
+        delegate.DUPLICATE_ATTRIB(to, from);
+    }
+
+    @Override
+    public int R_computeIdentical(Object x, Object y, int flags) {
+        RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags);
+        return delegate.R_computeIdentical(x, y, flags);
+    }
+
+    @Override
+    public void Rf_copyListMatrix(Object s, Object t, int byrow) {
+        RFFIUtils.traceUpCall("Rf_copyListMatrix", t, byrow);
+        delegate.Rf_copyListMatrix(s, t, byrow);
+    }
+
+    @Override
+    public void Rf_copyMatrix(Object s, Object t, int byrow) {
+        RFFIUtils.traceUpCall("Rf_copyMatrix", t, byrow);
+        delegate.Rf_copyMatrix(s, t, byrow);
+    }
+
+    @Override
+    public Object R_tryEval(Object expr, Object env, boolean silent) {
+        RFFIUtils.traceUpCall("R_tryEval", expr, env, silent);
+        return delegate.R_tryEval(expr, env, silent);
+    }
+
+    @Override
+    public Object R_ToplevelExec() {
+        RFFIUtils.traceUpCall("R_TopLevelExec");
+        return delegate.R_ToplevelExec();
+    }
+
+    @Override
+    public int RDEBUG(Object x) {
+        RFFIUtils.traceUpCall("RDEBUG", x);
+        return delegate.RDEBUG(x);
+    }
+
+    @Override
+    public void SET_RDEBUG(Object x, int v) {
+        RFFIUtils.traceUpCall("SET_RDEBUG", x, v);
+        delegate.SET_RDEBUG(x, v);
+    }
+
+    @Override
+    public int RSTEP(Object x) {
+        RFFIUtils.traceUpCall("RSTEP", x);
+        return delegate.RSTEP(x);
+    }
+
+    @Override
+    public void SET_RSTEP(Object x, int v) {
+        RFFIUtils.traceUpCall("SET_RSTEP", x, v);
+        delegate.SET_RSTEP(x, v);
+    }
+
+    @Override
+    public Object ENCLOS(Object x) {
+        RFFIUtils.traceUpCall("ENCLOS", x);
+        return delegate.ENCLOS(x);
+    }
+
+    @Override
+    public Object PRVALUE(Object x) {
+        RFFIUtils.traceUpCall("PRVALUE", x);
+        return delegate.PRVALUE(x);
+    }
+
+    @Override
+    public Object R_ParseVector(Object text, int n, Object srcFile) {
+        RFFIUtils.traceUpCall("R_ParseVector", text, n, srcFile);
+        return delegate.R_ParseVector(text, n, srcFile);
+    }
+
+    @Override
+    public Object R_lsInternal3(Object envArg, int allArg, int sortedArg) {
+        RFFIUtils.traceUpCall("R_lsInternal3", envArg, allArg, sortedArg);
+        return delegate.R_lsInternal3(envArg, allArg, sortedArg);
+    }
+
+    @Override
+    public String R_HomeDir() {
+        RFFIUtils.traceUpCall("R_HomeDir");
+        return delegate.R_HomeDir();
+    }
+
+    @Override
+    public void R_CleanUp(int sa, int status, int runlast) {
+        RFFIUtils.traceUpCall("R_Cleanup", sa, status, runlast);
+        delegate.R_CleanUp(sa, status, runlast);
+    }
+
+    @Override
+    public Object R_GlobalContext() {
+        RFFIUtils.traceUpCall("R_GlobalContext");
+        return delegate.R_GlobalContext();
+    }
+
+    @Override
+    public Object R_GlobalEnv() {
+        RFFIUtils.traceUpCall("R_GlobalEnv");
+        return delegate.R_GlobalEnv();
+    }
+
+    @Override
+    public Object R_BaseEnv() {
+        RFFIUtils.traceUpCall("R_BaseEnv");
+        return delegate.R_BaseEnv();
+    }
+
+    @Override
+    public Object R_BaseNamespace() {
+        RFFIUtils.traceUpCall("R_BaseNamespace");
+        return delegate.R_BaseNamespace();
+    }
+
+    @Override
+    public Object R_NamespaceRegistry() {
+        RFFIUtils.traceUpCall("R_NamespaceRegistry");
+        return delegate.R_NamespaceRegistry();
+    }
+
+    @Override
+    public int R_Interactive() {
+        RFFIUtils.traceUpCall("isInteractive");
+        return delegate.R_Interactive();
+    }
+
+    @Override
+    public int IS_S4_OBJECT(Object x) {
+        RFFIUtils.traceUpCall("isS4Object");
+        return delegate.IS_S4_OBJECT(x);
+    }
+
+    @Override
+    public void Rprintf(Object message) {
+        RFFIUtils.traceUpCall("Rprintf", message);
+        delegate.Rprintf(message);
+    }
+
+    @Override
+    public void GetRNGstate() {
+        RFFIUtils.traceUpCall("GetRNGstate");
+        delegate.GetRNGstate();
+    }
+
+    @Override
+    public void PutRNGstate() {
+        RFFIUtils.traceUpCall("PutRNGstate");
+        delegate.PutRNGstate();
+    }
+
+    @Override
+    public double unif_rand() {
+        RFFIUtils.traceUpCall("unif_rand");
+        return delegate.unif_rand();
+    }
+
+    @Override
+    public Object R_getGlobalFunctionContext() {
+        RFFIUtils.traceUpCall("R_getGlobalFunctionContext");
+        return delegate.R_getGlobalFunctionContext();
+    }
+
+    @Override
+    public Object R_getParentFunctionContext(Object c) {
+        RFFIUtils.traceUpCall("R_getParentFunctionContext");
+        return delegate.R_getParentFunctionContext(c);
+    }
+
+    @Override
+    public Object R_getContextEnv(Object c) {
+        RFFIUtils.traceUpCall("R_getContextEnv", c);
+        return delegate.R_getContextEnv(c);
+    }
+
+    @Override
+    public Object R_getContextFun(Object c) {
+        RFFIUtils.traceUpCall("R_getContextFun", c);
+        return delegate.R_getContextFun(c);
+    }
+
+    @Override
+    public Object R_getContextCall(Object c) {
+        RFFIUtils.traceUpCall("R_getContextCall", c);
+        return delegate.R_getContextCall(c);
+    }
+
+    @Override
+    public Object R_getContextSrcRef(Object c) {
+        RFFIUtils.traceUpCall("R_getContextSrcRef", c);
+        return delegate.R_getContextSrcRef(c);
+    }
+
+    @Override
+    public int R_insideBrowser() {
+        RFFIUtils.traceUpCall("R_insideBrowser");
+        return delegate.R_insideBrowser();
+    }
+
+    @Override
+    public int R_isGlobal(Object c) {
+        RFFIUtils.traceUpCall("R_isGlobal", c);
+        return delegate.R_isGlobal(c);
+    }
+
+    @Override
+    public int R_isEqual(Object x, Object y) {
+        RFFIUtils.traceUpCall("isEqual", x, y);
+        return delegate.R_isEqual(x, y);
+    }
+
+    @Override
+    public Object Rf_classgets(Object x, Object y) {
+        RFFIUtils.traceUpCall("Rf_classgets", x, y);
+        return delegate.Rf_classgets(x, y);
+    }
+
+    @Override
+    public RExternalPtr R_MakeExternalPtr(long addr, Object tag, Object prot) {
+        RFFIUtils.traceUpCall("R_MakeExternalPtr", addr, tag, prot);
+        return delegate.R_MakeExternalPtr(addr, tag, prot);
+    }
+
+    @Override
+    public long R_ExternalPtrAddr(Object x) {
+        RFFIUtils.traceUpCall("R_ExternalPtrAddr", x);
+        return delegate.R_ExternalPtrAddr(x);
+    }
+
+    @Override
+    public Object R_ExternalPtrTag(Object x) {
+        RFFIUtils.traceUpCall("R_ExternalPtrTag", x);
+        return delegate.R_ExternalPtrTag(x);
+    }
+
+    @Override
+    public Object R_ExternalPtrProt(Object x) {
+        RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+        return delegate.R_ExternalPtrProt(x);
+    }
+
+    @Override
+    public void R_SetExternalPtrAddr(Object x, long addr) {
+        RFFIUtils.traceUpCall("R_SetExternalPtrAddr", x);
+        delegate.R_SetExternalPtrAddr(x, addr);
+    }
+
+    @Override
+    public void R_SetExternalPtrTag(Object x, Object tag) {
+        RFFIUtils.traceUpCall("R_SetExternalPtrTag", x);
+        delegate.R_SetExternalPtrTag(x, tag);
+    }
+
+    @Override
+    public void R_SetExternalPtrProt(Object x, Object prot) {
+        RFFIUtils.traceUpCall("R_ExternalPtrProt", x);
+        delegate.R_SetExternalPtrProt(x, prot);
+    }
+
+    @Override
+    public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) {
+        RFFIUtils.traceUpCall("R_NewHashedEnv", parent, initialSize);
+        return delegate.R_NewHashedEnv(parent, initialSize);
+    }
+
+    @Override
+    public int PRSEEN(Object x) {
+        RFFIUtils.traceUpCall("PRSEEN", x);
+        return delegate.PRSEEN(x);
+    }
+
+    @Override
+    public Object PRENV(Object x) {
+        RFFIUtils.traceUpCall("PRENV", x);
+        return delegate.PRENV(x);
+    }
+
+    @Override
+    public Object R_PromiseExpr(Object x) {
+        RFFIUtils.traceUpCall("R_PromiseExpr", x);
+        return delegate.R_PromiseExpr(x);
+    }
+
+    @Override
+    public Object PRCODE(Object x) {
+        RFFIUtils.traceUpCall("PRCODE", x);
+        return delegate.PRCODE(x);
+    }
+
+    @Override
+    public Object R_CHAR(Object x) {
+        RFFIUtils.traceUpCall("R_CHAR", x);
+        return delegate.R_CHAR(x);
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
index 67f7371186c1adb6b6d202909e62e288c234aa72..30fc0680a855844113b4d879e6a786f60ed7dd7d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -483,7 +483,7 @@ public class ArgumentMatcher {
     }
 
     /**
-     * /** This method does the heavy lifting of re-arranging arguments by their names and position,
+     * This method does the heavy lifting of re-arranging arguments by their names and position,
      * also handling varargs.
      *
      * @param signature The signature (==names) of the supplied arguments
@@ -507,19 +507,27 @@ public class ArgumentMatcher {
         Arrays.fill(resultPermutation, MatchPermutation.UNMATCHED);
         Arrays.fill(resultSignature, ArgumentsSignature.UNMATCHED);
 
+        // MATCH in two phases: first by exact name (if we have actual: 'x', 'xa' and formal 'xa',
+        // then actual 'x' should not steal the position of 'xa'), then by partial
         boolean[] matchedSuppliedArgs = new boolean[signature.getLength()];
-        for (int suppliedIndex = 0; suppliedIndex < signature.getLength(); suppliedIndex++) {
-            String suppliedName = signature.getName(suppliedIndex);
-            if (suppliedName == null || suppliedName.isEmpty()) {
-                continue;
-            }
+        boolean[] formalsMatchedByExactName = new boolean[formalSignature.getLength()];
+        for (boolean byExactName : new boolean[]{true, false}) {
+            for (int suppliedIndex = 0; suppliedIndex < signature.getLength(); suppliedIndex++) {
+                String suppliedName = signature.getName(suppliedIndex);
+                boolean wasMatchedByExactName = !byExactName && matchedSuppliedArgs[suppliedIndex];
+                if (wasMatchedByExactName || suppliedName == null || suppliedName.isEmpty()) {
+                    continue;
+                }
 
-            // Search for argument name inside formal arguments
-            int formalIndex = findParameterPosition(formalSignature, suppliedName, resultPermutation, suppliedIndex, hasVarArgs, callingNode, varArgIndex, errorString, builtin);
-            if (formalIndex != MatchPermutation.UNMATCHED) {
-                resultPermutation[formalIndex] = suppliedIndex;
-                resultSignature[formalIndex] = suppliedName;
-                matchedSuppliedArgs[suppliedIndex] = true;
+                // Search for argument name inside formal arguments
+                int formalIndex = findParameterPosition(formalSignature, suppliedName, resultPermutation, suppliedIndex, hasVarArgs, callingNode, varArgIndex, errorString, builtin,
+                                formalsMatchedByExactName, byExactName);
+                if (formalIndex != MatchPermutation.UNMATCHED) {
+                    resultPermutation[formalIndex] = suppliedIndex;
+                    resultSignature[formalIndex] = suppliedName;
+                    formalsMatchedByExactName[formalIndex] = byExactName;
+                    matchedSuppliedArgs[suppliedIndex] = true;
+                }
             }
         }
 
@@ -536,7 +544,8 @@ public class ArgumentMatcher {
                         break outer;
                     }
                     if (!matchedSuppliedArgs[suppliedIndex]) {
-                        if (signature.getName(suppliedIndex) == null || signature.getName(suppliedIndex).isEmpty()) {
+                        String suppliedName = signature.getName(suppliedIndex);
+                        if (suppliedName == null || suppliedName.isEmpty()) {
                             // unnamed parameter, match by position
                             break;
                         }
@@ -622,14 +631,23 @@ public class ArgumentMatcher {
         return sum;
     }
 
+    private static <T> int findParameterPosition(ArgumentsSignature formalsSignature, String suppliedName, int[] resultPermutation, int suppliedIndex, boolean hasVarArgs, RBaseNode callingNode,
+                    int varArgIndex, IntFunction<String> errorString, RBuiltinDescriptor builtin, boolean[] formalsMatchedByExactName, boolean exactNameMatch) {
+        if (exactNameMatch) {
+            return findParameterPositionByExactName(formalsSignature, suppliedName, resultPermutation, hasVarArgs, callingNode, builtin);
+        } else {
+            return findParameterPositionByPartialName(formalsSignature, formalsMatchedByExactName, suppliedName, resultPermutation, suppliedIndex, hasVarArgs, callingNode, varArgIndex, errorString);
+        }
+    }
+
     /**
      * Searches for suppliedName inside formalNames and returns its (formal) index.
      *
      * @return The position of the given suppliedName inside the formalNames. Throws errors if the
      *         argument has been matched before
      */
-    private static <T> int findParameterPosition(ArgumentsSignature formalsSignature, String suppliedName, int[] resultPermutation, int suppliedIndex, boolean hasVarArgs, RBaseNode callingNode,
-                    int varArgIndex, IntFunction<String> errorString, RBuiltinDescriptor builtin) {
+    private static <T> int findParameterPositionByExactName(ArgumentsSignature formalsSignature, String suppliedName, int[] resultPermutation, boolean hasVarArgs,
+                    RBaseNode callingNode, RBuiltinDescriptor builtin) {
         assert suppliedName != null && !suppliedName.isEmpty();
         for (int i = 0; i < formalsSignature.getLength(); i++) {
             String formalName = formalsSignature.getName(i);
@@ -638,9 +656,8 @@ public class ArgumentMatcher {
                     if (resultPermutation[i] != MatchPermutation.UNMATCHED) {
                         if (builtin != null && builtin.getKind() == RBuiltinKind.PRIMITIVE && hasVarArgs) {
                             // for primitives, the first argument is matched, and the others are
-                            // folded
-                            // into varargs, for example:
-                            // x<-1:64; dim(x)<-c(4,4,2,2); x[1,drop=FALSE,1,drop=TRUE,-1]
+                            // folded into varargs, for example: x<-1:64; dim(x)<-c(4,4,2,2);
+                            // x[1,drop=FALSE,1,drop=TRUE,-1]
                             return MatchPermutation.UNMATCHED;
                         } else {
                             // Has already been matched: Error!
@@ -651,8 +668,25 @@ public class ArgumentMatcher {
                 }
             }
         }
+        return MatchPermutation.UNMATCHED;
+    }
+
+    /**
+     * Searches for partial match of suppliedName inside formalNames and returns its (formal) index.
+     *
+     * @return The position of the given suppliedName inside the formalNames. Throws errors if the
+     *         argument has been matched before
+     */
+    private static <T> int findParameterPositionByPartialName(ArgumentsSignature formalsSignature, boolean[] formalsMatchedByExactName, String suppliedName, int[] resultPermutation, int suppliedIndex,
+                    boolean hasVarArgs, RBaseNode callingNode, int varArgIndex, IntFunction<String> errorString) {
+        assert suppliedName != null && !suppliedName.isEmpty();
         int found = MatchPermutation.UNMATCHED;
         for (int i = 0; i < formalsSignature.getLength(); i++) {
+            if (formalsMatchedByExactName[i]) {
+                // was already matched by some exact match
+                continue;
+            }
+
             String formalName = formalsSignature.getName(i);
             if (formalName != null) {
                 if (formalName.startsWith(suppliedName) && ((varArgIndex != ArgumentsSignature.NO_VARARG && i < varArgIndex) || varArgIndex == ArgumentsSignature.NO_VARARG)) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
index e4d4d6172bd38663779bdd0a7fd6cc274250602e..3e3a70f6a376edeec50d7b697415317152945f19 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
@@ -205,14 +205,14 @@ abstract class S4Class extends RBaseNode {
      * but we probably cannot rely on this 100% of time and should use equals() method as backup.
      */
     @SuppressWarnings("unused")
-    @Specialization(contains = "getS4ClassCachedEqOp", guards = "classAttr.equals(cachedClassAttr)")
+    @Specialization(replaces = "getS4ClassCachedEqOp", guards = "classAttr.equals(cachedClassAttr)")
     protected RStringVector getS4ClassCachedEqMethod(String classAttr,
                     @Cached("classAttr") String cachedClassAttr,
                     @Cached("getS4ClassInternal(cachedClassAttr)") RStringVector s4Classes) {
         return s4Classes;
     }
 
-    @Specialization(contains = "getS4ClassCachedEqMethod")
+    @Specialization(replaces = "getS4ClassCachedEqMethod")
     protected RStringVector getS4Class(String classAttr) {
         return getS4ClassInternal(classAttr);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
index ad12519e53a2aa021a2a4b6712b94fcf50cc8afa..8ab60469026e8955106ad5d64b619bfa47097d21 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
@@ -251,7 +251,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
             verifyEnclosingAssumptions(frame);
             setupDispatchSlots(frame);
             saveArguments.execute(frame);
-            Object result = body.execute(frame);
+            Object result = body.visibleExecute(frame);
             normalExit.enter();
             return result;
         } catch (ReturnException ex) {
@@ -290,12 +290,12 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
              * has no exit handlers (by fiat), so any exceptions from onExits handlers will be
              * caught above.
              */
-            visibility.executeEndOfFunction(frame, this);
             if (argPostProcess != null) {
                 resetArgs.enter();
                 argPostProcess.execute(frame);
             }
             if (runOnExitHandlers) {
+                visibility.executeEndOfFunction(frame);
                 if (!noHandlerStackSlot.isValid() && frame.isObject(handlerStackSlot)) {
                     try {
                         RErrorHandling.restoreHandlerStack(frame.getObject(handlerStackSlot));
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..934265d3025a5bfeac28d296ede2b8cc06bf5a5a
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.function;
+
+import com.oracle.truffle.api.frame.MaterializedFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+
+/**
+ * Helper node to efficiently retrieve base environment's frame, e.g. for use as
+ * {@code genericDefFrame} parameter in {@link S3FunctionLookupNode}.
+ */
+public final class GetBaseEnvFrameNode extends Node {
+    private final ValueProfile frameAccessProfile = ValueProfile.createClassProfile();
+    private final ValueProfile baseEnvProfile = ValueProfile.createIdentityProfile();
+
+    public static GetBaseEnvFrameNode create() {
+        return new GetBaseEnvFrameNode();
+    }
+
+    public MaterializedFrame execute() {
+        REnvironment baseEnv = baseEnvProfile.profile(REnvironment.baseEnv());
+        return baseEnv.getFrame(frameAccessProfile);
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
index ba04478ae079e9bb81f2890f7828f1282f49dd57..5dfa52418410ca0d58b3cfb489bd1219dfa09f80 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ import com.oracle.truffle.api.CompilerAsserts;
 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.frame.Frame;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotKind;
 import com.oracle.truffle.api.frame.FrameSlotTypeException;
@@ -40,6 +39,7 @@ import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.InlineCacheNode;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -193,9 +193,7 @@ public class PromiseHelperNode extends RBaseNode {
             if (isInOriginFrame(frame, promise)) {
                 return promiseClosureCache.execute(frame, promise.getClosure());
             } else {
-                Frame promiseFrame = promiseFrameProfile.profile(promise.getFrame());
-                assert promiseFrame != null;
-                return promiseClosureCache.execute(wrapPromiseFrame(frame, promiseFrame), promise.getClosure());
+                return promiseClosureCache.execute(wrapPromiseFrame(frame, promiseFrameProfile.profile(promise.getFrame())), promise.getClosure());
             }
         } finally {
             promise.resetUnderEvaluation();
@@ -265,20 +263,16 @@ public class PromiseHelperNode extends RBaseNode {
             if (promise.isInOriginFrame(frame)) {
                 return promise.getClosure().eval(frame.materialize());
             } else {
-                Frame promiseFrame = promise.getFrame();
-                assert promiseFrame != null;
-
-                promiseFrame = wrapPromiseFrame(frame, promiseFrame);
-                return promise.getClosure().eval(promiseFrame.materialize());
+                return promise.getClosure().eval(wrapPromiseFrame(frame, promise.getFrame()));
             }
         } finally {
             promise.resetUnderEvaluation();
         }
     }
 
-    private static VirtualEvalFrame wrapPromiseFrame(VirtualFrame frame, Frame promiseFrame) {
-        return VirtualEvalFrame.create(promiseFrame.materialize(), RArguments.getFunction(promiseFrame),
-                        RCaller.createForPromise(RArguments.getCall(promiseFrame), frame));
+    private static VirtualEvalFrame wrapPromiseFrame(VirtualFrame frame, MaterializedFrame promiseFrame) {
+        assert promiseFrame != null;
+        return VirtualEvalFrame.create(promiseFrame, RArguments.getFunction(promiseFrame), RCaller.createForPromise(RArguments.getCall(promiseFrame), frame));
     }
 
     private static Object generateValueEagerSlowPath(VirtualFrame frame, int state, EagerPromiseBase promise) {
@@ -383,6 +377,8 @@ public class PromiseHelperNode extends RBaseNode {
     private static final int GENERIC = -2;
     @CompilationFinal private int cachedWrapIndex = UNINITIALIZED;
 
+    @Child private SetVisibilityNode visibility;
+
     /**
      * Returns {@link EagerPromise#getEagerValue()} profiled.
      */
@@ -419,6 +415,11 @@ public class PromiseHelperNode extends RBaseNode {
                 }
             }
         }
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
         return eagerValueProfile.profile(o);
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index e2a1b3c16c740ab471f92fce1816aadeaa72dc7e..5c9497e41bdfb24bd5d4092800123fee1682d397 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -48,7 +48,6 @@ import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.nodes.UnexpectedResultException;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
@@ -98,7 +97,6 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
-import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RFastPathNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -281,7 +279,8 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                     @Cached("createWithError()") S3FunctionLookupNode dispatchLookup,
                     @Cached("createIdentityProfile()") ValueProfile builtinProfile,
                     @Cached("createBinaryProfile()") ConditionProfile implicitTypeProfile,
-                    @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile) {
+                    @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile,
+                    @Cached("create()") GetBaseEnvFrameNode getBaseEnvFrameNode) {
         RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin());
         Object dispatchObject = dispatchArgument.execute(frame);
         // Cannot dispatch on REmpty
@@ -295,7 +294,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             S3Args s3Args;
             RFunction resultFunction;
             if (implicitTypeProfile.profile(type != null)) {
-                Result result = dispatchLookup.execute(frame, builtin.getGenericName(), type, null, frame.materialize(), REnvironment.baseEnv().getFrame());
+                Result result = dispatchLookup.execute(frame, builtin.getGenericName(), type, null, frame.materialize(), getBaseEnvFrameNode.execute());
                 if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) {
                     s3Args = null;
                 } else {
@@ -324,7 +323,8 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                     @Cached("createBinaryProfile()") ConditionProfile implicitTypeProfile,
                     @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile,
                     @Cached("createPromiseHelper()") PromiseCheckHelperNode promiseHelperNode,
-                    @Cached("createUninitializedExplicitCall()") FunctionDispatch call) {
+                    @Cached("createUninitializedExplicitCall()") FunctionDispatch call,
+                    @Cached("create()") GetBaseEnvFrameNode getBaseEnvFrameNode) {
         RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin());
         RArgsValuesAndNames argAndNames = (RArgsValuesAndNames) explicitArgs.execute(frame);
 
@@ -332,7 +332,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         S3Args s3Args;
         RFunction resultFunction;
         if (implicitTypeProfile.profile(type != null)) {
-            Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), REnvironment.baseEnv().getFrame());
+            Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), getBaseEnvFrameNode.execute());
             if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) {
                 s3Args = null;
             } else {
@@ -350,10 +350,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         return signature == null ? null : createArguments(null, false, false);
     }
 
-    protected ReadVariableNode createVarArgRead(CallArgumentsNode callArguments) {
-        return callArguments.containsVarArgsSymbol() ? ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any) : null;
-    }
-
     protected boolean isGroupGenericDispatch(RFunction function) {
         if (signature != null && signature.isEmpty()) {
             return false;
@@ -384,7 +380,8 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                     @Cached("createBinaryProfile()") ConditionProfile summaryGroupNaRmProfile,
                     @Cached("createBinaryProfile()") ConditionProfile summaryGroupProfile,
                     @Cached("createPromiseHelper()") PromiseCheckHelperNode promiseHelperNode,
-                    @Cached("createUninitializedExplicitCall()") FunctionDispatch call) {
+                    @Cached("createUninitializedExplicitCall()") FunctionDispatch call,
+                    @Cached("create()") GetBaseEnvFrameNode getBaseEnvFrameNode) {
 
         Object[] args = explicitArgs != null ? ((RArgsValuesAndNames) explicitArgs.execute(frame)).getArguments() : callArguments.evaluateFlattenObjects(frame, lookupVarArgs(frame));
         ArgumentsSignature argsSignature = explicitArgs != null ? ((RArgsValuesAndNames) explicitArgs.execute(frame)).getSignature() : callArguments.flattenNames(lookupVarArgs(frame));
@@ -404,13 +401,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         RStringVector typeX = classHierarchyNodeX.execute(promiseHelperNode.checkEvaluate(frame, args[typeXIdx]));
         Result resultX = null;
         if (implicitTypeProfileX.profile(typeX != null)) {
-            resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), REnvironment.baseEnv().getFrame());
+            resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), getBaseEnvFrameNode.execute());
         }
         Result resultY = null;
         if (args.length > 1 && dispatch == RDispatch.OPS_GROUP_GENERIC) {
             RStringVector typeY = classHierarchyNodeY.execute(promiseHelperNode.checkEvaluate(frame, args[1]));
             if (implicitTypeProfileY.profile(typeY != null)) {
-                resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), REnvironment.baseEnv().getFrame());
+                resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), getBaseEnvFrameNode.execute());
             }
         }
 
@@ -502,7 +499,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                 foreignCallArgCount = argumentsArray.length;
             }
             try {
-                Object result = ForeignAccess.sendExecute(foreignCall, frame, function, argumentsArray);
+                Object result = ForeignAccess.sendExecute(foreignCall, function, argumentsArray);
                 if (result instanceof Boolean) {
                     // convert to R logical
                     // TODO byte/short convert to int?
@@ -570,18 +567,15 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         return RCallNodeGen.create(src, arguments, signature, function);
     }
 
+    /**
+     * Creates a call that reads its explicit arguments from the frame under given identifier. This
+     * allows to invoke a function with argument(s) supplied by hand. Consider using
+     * {@link com.oracle.truffle.r.nodes.function.call.RExplicitCallNode} instead.
+     */
     public static RCallNode createExplicitCall(Object explicitArgsIdentifier) {
         return RCallNodeGen.create(RSyntaxNode.INTERNAL, explicitArgsIdentifier, null);
     }
 
-    static RBuiltinRootNode findBuiltinRootNode(RootCallTarget callTarget) {
-        RootNode root = callTarget.getRootNode();
-        if (root instanceof RBuiltinRootNode) {
-            return (RBuiltinRootNode) root;
-        }
-        return null;
-    }
-
     static boolean needsSplitting(RootCallTarget target) {
         RRootNode root = (RRootNode) target.getRootNode();
         return root.containsDispatch() || root.needsSplitting();
@@ -809,7 +803,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                             arg = casts[i].execute(arg);
                         }
                     } else {
-                        assert casts.length <= i || casts[i] == null : "no casts allowed on non-evaluated arguments";
+                        assert casts.length <= i || casts[i] == null : "no casts allowed on non-evaluated arguments in builtin " + builtinDescriptor.getName();
                         if (arg instanceof RPromise || arg instanceof RMissing) {
                             if (!nonWrapSeen[i]) {
                                 CompilerDirectives.transferToInterpreterAndInvalidate();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
index af88432eaad177fe0fbbec300659454e9c2621ea..51c882d0911cd9b666a037cb5c548f6145dfe1f8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,10 +29,13 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RDeparse;
+import com.oracle.truffle.r.runtime.RDispatch;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RVisibility;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RSpecialFactory;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -119,10 +122,12 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
 
     @Child private RNode functionNode;
     @Child private RNode special;
+    @Child private SetVisibilityNode visibility;
 
     private final RSyntaxNode[] arguments;
     private final ArgumentsSignature signature;
     public final RFunction expectedFunction;
+    private final RVisibility visible;
 
     /**
      * If this is true, then any bailout should simply be forwarded by re-throwing the exception.
@@ -142,6 +147,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         this.functionNode = functionNode;
         this.arguments = arguments;
         this.signature = signature;
+        this.visible = expectedFunction.getRBuiltin().getVisibility();
     }
 
     /**
@@ -187,9 +193,12 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         String name = ((RSyntaxLookup) syntaxFunction).getIdentifier();
         RBuiltinDescriptor builtinDescriptor = RContext.lookupBuiltinDescriptor(name);
         if (builtinDescriptor == null) {
-            // no builtint -> bail out
+            // no builtin -> bail out
             return null;
         }
+        RDispatch dispatch = builtinDescriptor.getDispatch();
+        // it's ok to evaluate promises for args that would be forced by dispatch anyway
+        int evaluatedArgs = dispatch == RDispatch.OPS_GROUP_GENERIC ? 2 : (dispatch == RDispatch.INTERNAL_GENERIC || dispatch.isGroupGeneric()) ? 1 : 0;
         RSpecialFactory specialCall = builtinDescriptor.getSpecialCall();
         if (specialCall == null) {
             // no special call definition -> bail out
@@ -202,7 +211,15 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
                 localArguments[i] = arg.asRNode();
             } else {
                 if (arg instanceof RSyntaxLookup) {
-                    localArguments[i] = new PeekLocalVariableNode(((RSyntaxLookup) arg).getIdentifier());
+                    String lookup = ((RSyntaxLookup) arg).getIdentifier();
+                    if (ArgumentsSignature.VARARG_NAME.equals(lookup)) {
+                        return null;
+                    }
+                    if (i < evaluatedArgs) {
+                        localArguments[i] = arg.asRNode();
+                    } else {
+                        localArguments[i] = new PeekLocalVariableNode(lookup);
+                    }
                 } else if (arg instanceof RSyntaxConstant) {
                     localArguments[i] = RContext.getASTBuilder().process(arg).asRNode();
                 } else {
@@ -298,6 +315,17 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         return execute(frame, functionNode.execute(frame));
     }
 
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
+        Object result = execute(frame, functionNode.execute(frame));
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, visible);
+        return result;
+    }
+
     @Override
     public RSyntaxElement getSyntaxLHS() {
         return functionNode == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : functionNode.asRSyntaxNode();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
index 2ddb5474316dbf7260cda12b317c9002b32fb671..bbce4bf49e0fc2c3d86a9cc6fc882f2d635a9e4e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments.S3Args;
+import com.oracle.truffle.r.runtime.RDispatch;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -177,6 +178,21 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
         }
     }
 
+    /**
+     * Searches for the correct S3 method for given function name and vector of class names.
+     *
+     * @param frame
+     * @param genericName The name of the generic function to look for, e.g. 'length'.
+     * @param type Vector of classes, if it is e.g. 'myclass', then this will search for
+     *            'length.myclass'.
+     * @param group See {@link RDispatch} and R documentation on "group" dispatch.
+     * @param callerFrame The frame of the caller will be starting point of the search.
+     * @param genericDefFrame This frame will be searched for special variables influencing the
+     *            lookup, e.g. .__S3MethodsTable__. Any other caller than {@code UseMethod} or
+     *            {@code NextMethod}, should supply base environment's frame using
+     *            {@link GetBaseEnvFrameNode}.
+     * @return Information about the lookup result.
+     */
     public abstract S3FunctionLookupNode.Result execute(VirtualFrame frame, String genericName, RStringVector type, String group, MaterializedFrame callerFrame, MaterializedFrame genericDefFrame);
 
     private static UseMethodFunctionLookupCachedNode specialize(VirtualFrame frame, String genericName, RStringVector type, String group, MaterializedFrame callerFrame,
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
index cb11340263cd982c1e93c2433109788a5a8d6ddb..ebc6853f82b99c2b42960331e645ed0d5de65090 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.function;
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -46,13 +47,23 @@ public abstract class WrapArgumentBaseNode extends RNode {
         return operand;
     }
 
+    @Override
+    public final void voidExecute(VirtualFrame frame) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
     @Override
     public final Object execute(VirtualFrame frame) {
-        assert operand != null;
         Object result = operand.execute(frame);
         return execute(frame, result);
     }
 
+    @Override
+    public final Object visibleExecute(VirtualFrame frame) {
+        Object result = operand.visibleExecute(frame);
+        return execute(frame, result);
+    }
+
     public Object execute(VirtualFrame frame, Object result) {
         if (isShareable.profile(result instanceof RSharingAttributeStorage)) {
             return handleShareable(frame, (RSharingAttributeStorage) result);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java
index bb8e9eb11a7da751329c6c5205821c8ad125a85c..d319b9f8c05f15928c8e2d3def5fb1b8d14fc6b6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -72,7 +72,7 @@ public abstract class CallRFunctionCachedNode extends Node {
     protected Object call(VirtualFrame frame, @SuppressWarnings("unused") CallTarget target, Object[] arguments, RCaller caller,
                     @Cached("createDirectCallNode(target)") DirectCallNode callNode) {
         try {
-            return callNode.call(frame, arguments);
+            return callNode.call(arguments);
         } finally {
             visibility.executeAfterCall(frame, caller);
         }
@@ -86,7 +86,7 @@ public abstract class CallRFunctionCachedNode extends Node {
     protected Object call(VirtualFrame frame, CallTarget target, Object[] arguments, RCaller caller,
                     @Cached("createIndirectCallNode()") IndirectCallNode callNode) {
         try {
-            return callNode.call(frame, target, arguments);
+            return callNode.call(target, arguments);
         } finally {
             visibility.executeAfterCall(frame, caller);
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
index 9b6737a530c67631391b3dbc6d24c3a9d67a484b..02a315c52e90c6df7363da15e1a207af7b8876c0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -55,7 +55,7 @@ public final class CallRFunctionNode extends Node {
                     MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) {
         Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs);
         try {
-            return callNode.call(frame, callArgs);
+            return callNode.call(callArgs);
         } finally {
             visibility.executeAfterCall(frame, caller);
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
index 5b48ec10193c4ede8faf5340e4ed14b5eee1032d..d19da1dc99641c190803d58b675f2abdc8a19b64 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@ import com.oracle.truffle.r.runtime.Arguments;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
@@ -92,7 +93,13 @@ public abstract class PrepareArguments extends Node {
         private static RArgsValuesAndNames executeArgs(RNode[] arguments, ArgumentsSignature suppliedSignature, VirtualFrame frame) {
             Object[] result = new Object[arguments.length];
             for (int i = 0; i < arguments.length; i++) {
-                result[i] = arguments[i].execute(frame);
+                Object value = arguments[i].execute(frame);
+                if (CompilerDirectives.inInterpreter()) {
+                    if (value == null) {
+                        throw RInternalError.shouldNotReachHere("Java 'null' not allowed in arguments");
+                    }
+                }
+                result[i] = value;
             }
             return new RArgsValuesAndNames(result, suppliedSignature);
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/RExplicitBaseEnvCallDispatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/RExplicitBaseEnvCallDispatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..61d2917f3e49cea47cc8482e0d800aae2c874f41
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/RExplicitBaseEnvCallDispatcher.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.function.call;
+
+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.nodes.Node;
+import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
+import com.oracle.truffle.r.nodes.function.GetBaseEnvFrameNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.RFunction;
+
+/**
+ * Helper node that allows to call a function from base environment by name. This node makes
+ * assumption that a function in base environment is not going to change and can be cached.
+ */
+public abstract class RExplicitBaseEnvCallDispatcher extends Node {
+
+    @Child private LocalReadVariableNode readFunc;
+    @Child RExplicitCallNode callNode = RExplicitCallNode.create();
+    @Child GetBaseEnvFrameNode getBaseEnvFrameNode = GetBaseEnvFrameNode.create();
+
+    public RExplicitBaseEnvCallDispatcher(LocalReadVariableNode readFunc) {
+        this.readFunc = readFunc;
+    }
+
+    public static RExplicitBaseEnvCallDispatcher create(String funcName) {
+        return RExplicitBaseEnvCallDispatcherNodeGen.create(LocalReadVariableNode.create(funcName, true));
+    }
+
+    /**
+     * Helper method that wraps the argument into {@link RArgsValuesAndNames} and invokes the
+     * {@link #execute(VirtualFrame, RArgsValuesAndNames)} method.
+     */
+    public Object call(VirtualFrame frame, Object target) {
+        return execute(frame, new RArgsValuesAndNames(new Object[]{target}, ArgumentsSignature.empty(1)));
+    }
+
+    public abstract Object execute(VirtualFrame frame, RArgsValuesAndNames arguments);
+
+    @Specialization
+    public Object doCached(VirtualFrame frame, RArgsValuesAndNames arguments,
+                    @Cached("getFunction(frame)") RFunction function) {
+        return callNode.execute(frame, function, arguments);
+    }
+
+    RFunction getFunction(VirtualFrame frame) {
+        Object function = readFunc.execute(frame, getBaseEnvFrameNode.execute());
+        assert function instanceof RFunction : "unexpected that '" + readFunc.getIdentifier() + "' in base environment is not a function";
+        return (RFunction) function;
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/RExplicitCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/RExplicitCallNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f6354db2fe120fa7eb56e0ebabe4607b0d7475f
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/RExplicitCallNode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.function.call;
+
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.FrameSlot;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.nodes.access.FrameSlotNode;
+import com.oracle.truffle.r.nodes.function.RCallBaseNode;
+import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.RFunction;
+
+/**
+ * Helper node that allows to call a given function with explicit arguments.
+ */
+public abstract class RExplicitCallNode extends Node {
+    public static RExplicitCallNode create() {
+        return RExplicitCallNodeGen.create();
+    }
+
+    public abstract Object execute(VirtualFrame frame, RFunction function, RArgsValuesAndNames args);
+
+    @Specialization
+    Object doCall(VirtualFrame frame, RFunction function, RArgsValuesAndNames args,
+                    @SuppressWarnings("unused") @Cached("createArgsIdentifier()") Object argsIdentifier,
+                    @Cached("createExplicitCall(argsIdentifier)") RCallBaseNode call,
+                    @Cached("createFrameSlotNode(argsIdentifier)") FrameSlotNode argumentsSlot) {
+        FrameSlot argsFrameSlot = argumentsSlot.executeFrameSlot(frame);
+        try {
+            frame.setObject(argsFrameSlot, args);
+            return call.execute(frame, function);
+        } finally {
+            frame.setObject(argsFrameSlot, null);
+        }
+    }
+
+    static Object createArgsIdentifier() {
+        return new Object();
+    }
+
+    static RCallBaseNode createExplicitCall(Object argsIdentifier) {
+        return RCallNode.createExplicitCall(argsIdentifier);
+    }
+
+    static FrameSlotNode createFrameSlotNode(Object argsIdentifier) {
+        return FrameSlotNode.createTemp(argsIdentifier, true);
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java
index dda1306eb2a7120dca13660a086e6fcd7bb873c3..b5d62266067b674b99932bf142ce193d5c835727 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java
@@ -56,7 +56,7 @@ public abstract class ReuseNonSharedNode extends Node {
         return value;
     }
 
-    @Specialization(contains = "getStorage")
+    @Specialization(replaces = "getStorage")
     protected static RShareable getRShareable(RShareable value,
                     @Cached("createBinaryProfile()") ConditionProfile isSharedProfile) {
         if (isSharedProfile.profile(value.isShared())) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CollectArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CollectArgumentsNode.java
index 8cae02ab03e08793add687916a8f821fb1e42617..0be21e8e3d00446e09e77aa542f44d923380e5a2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CollectArgumentsNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CollectArgumentsNode.java
@@ -61,11 +61,10 @@ public abstract class CollectArgumentsNode extends RBaseNode {
         return reads;
     }
 
-    @SuppressWarnings("unused")
     @ExplodeLoop
     @Specialization(limit = "CACHE_LIMIT", guards = {"cachedSignature == signature"})
-    protected Object[] combineCached(VirtualFrame frame, ArgumentsSignature signature,
-                    @Cached("signature") ArgumentsSignature cachedSignature,
+    protected Object[] combineCached(VirtualFrame frame, @SuppressWarnings("unused") ArgumentsSignature signature,
+                    @Cached("signature") @SuppressWarnings("unused") ArgumentsSignature cachedSignature,
                     @Cached("createArgs(signature, frame)") Node[] reads) {
         Object[] result = new Object[reads.length];
         for (int i = 0; i < reads.length; i++) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CombineSignaturesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CombineSignaturesNode.java
index b360a6e5aa9cee0c359b52901ed7dae3ab61e7c9..35e5972874d5c1619d1237938ffc2f489560f5d4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CombineSignaturesNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/CombineSignaturesNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,12 +64,10 @@ public abstract class CombineSignaturesNode extends RBaseNode {
         return new RArgsValuesAndNames(leftValues, left);
     }
 
-    @SuppressWarnings("unused")
-    @Specialization(limit = "CACHE_LIMIT", guards = {"left == leftCached", "right == rightCached", "leftValues == leftValuesCached", "!right.isEmpty()", "!left.isEmpty()"})
-    protected RArgsValuesAndNames combineCached(ArgumentsSignature left, Object[] leftValues, ArgumentsSignature right, Object[] rightValues,
-                    @Cached("left") ArgumentsSignature leftCached,
-                    @Cached("leftValues") Object[] leftValuesCached,
-                    @Cached("right") ArgumentsSignature rightCached,
+    @Specialization(limit = "CACHE_LIMIT", guards = {"left == leftCached", "right == rightCached", "!right.isEmpty()", "!left.isEmpty()"})
+    protected RArgsValuesAndNames combineCached(ArgumentsSignature left, Object[] leftValues, @SuppressWarnings("unused") ArgumentsSignature right, Object[] rightValues,
+                    @Cached("left") @SuppressWarnings("unused") ArgumentsSignature leftCached,
+                    @Cached("right") @SuppressWarnings("unused") ArgumentsSignature rightCached,
                     @Cached("combine(left, leftValues, right)") CombineResult resultCached,
                     @Cached("createBinaryProfile()") ConditionProfile shufflingProfile,
                     @Cached("createBinaryProfile()") ConditionProfile noVarArgsProfile) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java
index 27838bcaf8218bbeef4e95fd0c77d2e54b760066..1ac6ee892212d1d89aa7d594271e67a34642e026 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,7 @@ public final class MissingNode extends OperatorNode {
             return node.execute(frame);
         }
 
-        @Specialization(contains = "checkCached")
+        @Specialization(replaces = "checkCached")
         public static boolean check(Frame frame, String symbol) {
             return RMissingHelper.isMissingArgument(frame, symbol);
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
index c20ab69256fd7633f839275c9f7ebe88f9db6cbc..a259f498adbd9a3d08e22058bae9dd8d0ecf311c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -88,19 +87,11 @@ public final class SetVisibilityNode extends Node {
      * Needs to be called at the end of each function, so that the visibility is transferred from
      * the current frame into the {@link RCaller}.
      */
-    public void executeEndOfFunction(VirtualFrame frame, RootNode root) {
+    public void executeEndOfFunction(VirtualFrame frame) {
         ensureFrameSlot(frame);
         try {
             if (frame.isBoolean(frameSlot)) {
                 RArguments.getCall(frame).setVisibility(frame.getBoolean(frameSlot) == Boolean.TRUE);
-            } else {
-                CompilerDirectives.transferToInterpreter();
-                /*
-                 * Most likely the (only) builtin call in the function was configured to
-                 * RVisibility.CUSTOM and didn't actually set the visibility. Another possible
-                 * problem is a node that is created by RASTBuilder that does not set visibility.
-                 */
-                throw RInternalError.shouldNotReachHere("visibility not set at the end of " + root.getName());
             }
         } catch (FrameSlotTypeException e) {
             throw RInternalError.shouldNotReachHere(e);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java
index 9daa82af3e5143b1da79fad18d38b3804ba3ccfc..dd6ba6f6a16f2c99731e4d0a9f662530dc94afbb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java
@@ -54,7 +54,7 @@ public abstract class AsS4 extends Node {
             if (complete != 0) {
                 if (getS4DataSlot == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    getS4DataSlot = GetS4DataSlotNodeGen.create(RType.Any);
+                    getS4DataSlot = insert(GetS4DataSlotNodeGen.create(RType.Any));
 
                 }
                 RTypedValue value = getS4DataSlot.executeObject(obj);
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 ffaa9c8bc3a258a36fe8bb69c5dc6d75bc663ffc..ab3e9a0db9a0c56ddba08478419996dbad12ee24 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
@@ -91,7 +91,7 @@ public abstract class DispatchGeneric extends RBaseNode {
         return dispatchInternal(frame, mtable, classes, fdef, fname, method);
     }
 
-    @Specialization(contains = "dispatchCached")
+    @Specialization(replaces = "dispatchCached")
     protected Object dispatch(VirtualFrame frame, REnvironment mtable, RStringVector classes, RFunction fdef, String fname) {
         String dispatchString = createDispatchString(classes);
         RFunction method = (RFunction) mtable.get(dispatchString);
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 0daaaae68e23110b5bfb2d218919f6a25d46d7ea..25920e40449e25802068ac9f1583534586c7af60 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
@@ -14,7 +14,6 @@ package com.oracle.truffle.r.nodes.objects;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.builtin;
 
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -22,9 +21,9 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 // transcribed from src/library/methods/src/utils.c
 public abstract class GetPrimName extends RExternalBuiltinNode.Arg1 {
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg(0).defaultError(RError.NO_CALLER, RError.Message.GENERIC, "'R_get_primname' called on a non-primitive").mustNotBeNull().mustBe(builtin());
+    static {
+        Casts casts = new Casts(GetPrimName.class);
+        casts.arg(0).defaultError(RError.NO_CALLER, RError.Message.GENERIC, "'R_get_primname' called on a non-primitive").mustBe(builtin());
     }
 
     @Specialization(guards = "f.isBuiltin()")
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 748dd665f74f59189f17a4bb285a2631bf21adb4..449eabf4bdbd68285bb9edc49a05224efdbef6b9 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
@@ -51,10 +51,10 @@ abstract class LoadMethod extends RBaseNode {
     @Child private GetFixedAttributeNode definedAttrAccess = GetFixedAttributeNode.create(RRuntime.R_DEFINED);
     @Child private GetFixedAttributeNode nextMethodAttrAccess = GetFixedAttributeNode.create(RRuntime.R_NEXT_METHOD);
     @Child private GetFixedAttributeNode sourceAttrAccess = GetFixedAttributeNode.create(RRuntime.R_SOURCE);
-    @Child private WriteLocalFrameVariableNode writeRTarget = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_TARGET, null, WriteVariableNode.Mode.REGULAR);
-    @Child private WriteLocalFrameVariableNode writeRDefined = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_DEFINED, null, WriteVariableNode.Mode.REGULAR);
-    @Child private WriteLocalFrameVariableNode writeRNextMethod = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_NEXT_METHOD, null, WriteVariableNode.Mode.REGULAR);
-    @Child private WriteLocalFrameVariableNode writeRMethod = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_METHOD, null, WriteVariableNode.Mode.REGULAR);
+    @Child private WriteLocalFrameVariableNode writeRTarget = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_TARGET, WriteVariableNode.Mode.REGULAR, null);
+    @Child private WriteLocalFrameVariableNode writeRDefined = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_DEFINED, WriteVariableNode.Mode.REGULAR, null);
+    @Child private WriteLocalFrameVariableNode writeRNextMethod = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_NEXT_METHOD, WriteVariableNode.Mode.REGULAR, null);
+    @Child private WriteLocalFrameVariableNode writeRMethod = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_METHOD, WriteVariableNode.Mode.REGULAR, null);
     @Child private LocalReadVariableNode methodsEnvRead = LocalReadVariableNode.create("methods", true);
     @Child private ReadVariableNode loadMethodFind;
     @Child private CallRFunctionNode loadMethodCall;
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 675a6acb09ec5c919cc36f44b4ccddc8f8a26175..44d51c9a1b090d243560b7404add7150eccc27f1 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,13 +12,14 @@
  */
 package com.oracle.truffle.r.nodes.objects;
 
+import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
+
 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;
 import com.oracle.truffle.r.nodes.unary.DuplicateNode;
@@ -31,9 +32,9 @@ import com.oracle.truffle.r.runtime.data.RS4Object;
 // transcribed from src/main/objects.c
 public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
 
-    @Child private AccessSlotNode accessSlotVirtual = AccessSlotNodeGen.create(true, null, null);
-    @Child private AccessSlotNode accessSlotClassName = AccessSlotNodeGen.create(true, null, null);
-    @Child private AccessSlotNode accessSlotPrototypeName = AccessSlotNodeGen.create(true, null, null);
+    @Child private AccessSlotNode accessSlotVirtual = AccessSlotNodeGen.create(true);
+    @Child private AccessSlotNode accessSlotClassName = AccessSlotNodeGen.create(true);
+    @Child private AccessSlotNode accessSlotPrototypeName = AccessSlotNodeGen.create(true);
     @Child private DuplicateNode duplicate = DuplicateNodeGen.create(true);
     @Child private GetFixedAttributeNode pckgAttrAccess = GetFixedAttributeNode.create(RRuntime.PCKG_ATTR_KEY);
     @Child private SetClassAttributeNode setClassAttrNode;
@@ -41,15 +42,12 @@ public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
     @Child private CastNode castStringScalar;
     @Child private CastNode castLogicalScalar;
     {
-        CastBuilder builder = new CastBuilder();
-        builder.arg(0).asStringVector().findFirst(RRuntime.STRING_NA);
-        builder.arg(1).asLogicalVector().findFirst(RRuntime.LOGICAL_NA);
-        castStringScalar = builder.getCasts()[0];
-        castLogicalScalar = builder.getCasts()[1];
+        castStringScalar = newCastBuilder().asStringVector().findFirst(RRuntime.STRING_NA).buildCastNode();
+        castLogicalScalar = newCastBuilder().asLogicalVector().findFirst(RRuntime.LOGICAL_NA).buildCastNode();
     }
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
+    static {
+        Casts casts = new Casts(NewObject.class);
         // TODO: should we change the message to (incompatible) "Java level ..."?
         casts.arg(0).mustNotBeNull(RError.NO_CALLER, RError.Message.GENERIC, "C level NEW macro called with null class definition pointer");
     }
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 d8c4d356fdd5fb375694225ed70b84d5f8c62a1d..0290ce2ffd7ec6ee4102cdbf940166784e222b9f 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
@@ -429,7 +429,7 @@ public final class BinaryMapNode extends RBaseNode {
             indexedAction.perform(node, store, 0, left, 0, right, 0);
         }
 
-        @Specialization(contains = "doScalarScalar", guards = {"leftLength == 1"})
+        @Specialization(replaces = "doScalarScalar", guards = {"leftLength == 1"})
         @SuppressWarnings("unused")
         protected void doScalarVector(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
                         @Cached("createCountingProfile()") LoopConditionProfile profile) {
@@ -439,7 +439,7 @@ public final class BinaryMapNode extends RBaseNode {
             }
         }
 
-        @Specialization(contains = "doScalarScalar", guards = {"rightLength == 1"})
+        @Specialization(replaces = "doScalarScalar", guards = {"rightLength == 1"})
         @SuppressWarnings("unused")
         protected void doVectorScalar(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
                         @Cached("createCountingProfile()") LoopConditionProfile profile) {
@@ -463,7 +463,7 @@ public final class BinaryMapNode extends RBaseNode {
             return max % min == 0;
         }
 
-        @Specialization(contains = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(leftLength, rightLength)"})
+        @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(leftLength, rightLength)"})
         protected void doMultiplesLeft(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
                         @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
                         @Cached("createCountingProfile()") LoopConditionProfile rightProfile) {
@@ -478,7 +478,7 @@ public final class BinaryMapNode extends RBaseNode {
             }
         }
 
-        @Specialization(contains = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(rightLength, leftLength)"})
+        @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(rightLength, leftLength)"})
         protected void doMultiplesRight(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
                         @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
                         @Cached("createCountingProfile()") LoopConditionProfile rightProfile) {
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 e759e0cb5199405ecb80f7730b96742d9a8e3f24..b901cd67808a18a7865db0696168a7a7a45221b9 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
@@ -337,7 +337,7 @@ public final class UnaryMapNode extends RBaseNode {
             indexedAction.perform(node, store, 0, operand, 0);
         }
 
-        @Specialization(contains = "doScalar")
+        @Specialization(replaces = "doScalar")
         protected void doScalarVector(UnaryMapFunctionNode node, Object store, RAbstractVector operand, int operandLength,
                         @Cached("createCountingProfile()") LoopConditionProfile profile) {
             profile.profileCounted(operandLength);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java
index 7451b155571bf22d9c1376c659a5846614f2465a..1eb02abccfe7c295dd4749a7c44cbd72ccf2b28a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java
@@ -61,7 +61,7 @@ public final class RQueryVisitor implements RSyntaxNodeVisitor<RSyntaxNode> {
 
     @Override
     public final RSyntaxNode visit(final WriteLocalFrameVariableNode var) {
-        return WriteLocalFrameVariableNode.create((String) var.getName(), var.getRhs().asRSyntaxNode().accept(this).asRNode(), var.getMode()).asRSyntaxNode();
+        return WriteLocalFrameVariableNode.create(var.getName(), var.mode, var.getRhs().asRSyntaxNode().accept(this).asRNode()).asRSyntaxNode();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/BypassNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/BypassNode.java
index 2493bca82e507ee17f8dfe0450e1c0ac5c69220f..59ae7e9a2c906bb286a56e2e9c677fb386fc7d0c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/BypassNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/BypassNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@ import com.oracle.truffle.r.nodes.builtin.ArgumentMapper;
 import com.oracle.truffle.r.nodes.builtin.casts.MessageData;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineConfig;
 import com.oracle.truffle.r.nodes.builtin.casts.PipelineToCastNode.ArgumentMapperFactory;
+import com.oracle.truffle.r.nodes.unary.ConditionalMapNode.PipelineReturnException;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -102,7 +103,11 @@ public abstract class BypassNode extends CastNode {
 
     protected final Object executeAfterFindFirst(Object value) {
         if (afterFindFirst != null) {
-            return afterFindFirst.execute(value);
+            try {
+                return afterFindFirst.execute(value);
+            } catch (PipelineReturnException ret) {
+                return ret.getResult();
+            }
         } else {
             return value;
         }
@@ -160,7 +165,11 @@ public abstract class BypassNode extends CastNode {
 
     @Specialization(guards = "isNotHandled(x)")
     public Object handleOthers(Object x) {
-        return noHead ? x : wrappedHead.execute(x);
+        try {
+            return noHead ? x : wrappedHead.execute(x);
+        } catch (PipelineReturnException ret) {
+            return ret.getResult();
+        }
     }
 
     protected boolean isNotHandled(Object x) {
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 860e6461885dec3ed983f115cc5e3e2b81ca9abe..f136727e66301ca5e52345e87ad452d418b737a3 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,15 +34,18 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNames
 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.RError.Message;
 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.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 public abstract class CastBaseNode extends CastNode {
 
@@ -59,16 +62,39 @@ public abstract class CastBaseNode extends CastNode {
     private final boolean preserveDimensions;
     private final boolean preserveAttributes;
 
+    protected final RBaseNode messageCallObj;
+
+    /**
+     * GnuR provides several, sometimes incompatible, ways to coerce given value to given type. This
+     * flag tells the cast node that it should behave in a way compatible with functions exposed by
+     * the native interface.
+     */
+    private final boolean forRFFI;
+
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
+        this(preserveNames, preserveDimensions, preserveAttributes, false, messageCallObj);
+    }
+
     protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        this(preserveNames, preserveDimensions, preserveAttributes, false, null);
+    }
+
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        this(preserveNames, preserveDimensions, preserveAttributes, forRFFI, null);
+    }
+
+    protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI, RBaseNode messageCallObj) {
         this.preserveNames = preserveNames;
         this.preserveDimensions = preserveDimensions;
         this.preserveAttributes = preserveAttributes;
+        this.forRFFI = forRFFI;
         if (preserveDimensions) {
             getDimNamesNode = GetDimNamesAttributeNode.create();
         }
+        this.messageCallObj = messageCallObj == null ? this : messageCallObj;
     }
 
-    public boolean preserveNames() {
+    public final boolean preserveNames() {
         return preserveNames;
     }
 
@@ -76,7 +102,7 @@ public abstract class CastBaseNode extends CastNode {
         return preserveDimensions;
     }
 
-    public boolean preserveAttributes() {
+    public final boolean preserveAttributes() {
         return preserveAttributes;
     }
 
@@ -84,7 +110,7 @@ public abstract class CastBaseNode extends CastNode {
 
     protected RError throwCannotCoerceListError(String type) {
         listCoercionErrorBranch.enter();
-        throw RError.error(this, RError.Message.LIST_COERCION, type);
+        throw RError.error(messageCallObj, RError.Message.LIST_COERCION, type);
     }
 
     protected int[] getPreservedDimensions(RAbstractContainer operand) {
@@ -124,6 +150,10 @@ public abstract class CastBaseNode extends CastNode {
     @TruffleBoundary
     protected Object doOther(Object value) {
         Object mappedValue = RRuntime.asAbstractVector(value);
+        return forRFFI ? doOtherRFFI(mappedValue) : doOtherDefault(mappedValue);
+    }
+
+    protected Object doOtherDefault(Object mappedValue) {
         if (mappedValue instanceof REnvironment) {
             throw RError.error(RError.SHOW_CALLER, RError.Message.ENVIRONMENTS_COERCE);
         } else if (mappedValue instanceof RTypedValue) {
@@ -134,4 +164,13 @@ public abstract class CastBaseNode extends CastNode {
             throw RInternalError.shouldNotReachHere("unexpected value of type " + (mappedValue == null ? "null" : mappedValue.getClass()));
         }
     }
+
+    protected Object doOtherRFFI(Object mappedValue) {
+        if (mappedValue instanceof RTypedValue) {
+            RError.warning(RError.SHOW_CALLER2, Message.CANNOT_COERCE_RFFI, ((RTypedValue) mappedValue).getRType().getName(), getTargetType().getName());
+        } else if (mappedValue instanceof TruffleObject) {
+            throw RError.error(RError.SHOW_CALLER2, RError.Message.CANNOT_COERCE, "truffleobject", getTargetType().getName());
+        }
+        return RNull.instance;
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
index 00a0678e90084e096d056dc9b8e8d2ec4cb8a1c0..3d8fb9edf3cb50b7c240b346f6b6ecd014af103c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java
@@ -45,6 +45,7 @@ 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.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
@@ -62,8 +63,16 @@ public abstract class CastComplexNode extends CastBaseNode {
 
     public abstract Object executeComplex(Object o);
 
+    protected CastComplexNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+        super(preserveNames, preserveDimensions, preserveAttributes, messageCallerObj);
+    }
+
     protected CastComplexNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastComplexNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Child private CastComplexNode recursiveCastComplex;
@@ -248,7 +257,7 @@ public abstract class CastComplexNode extends CastBaseNode {
                 }
             }
         }
-        RComplexVector ret = RDataFactory.createComplexVector(result, !seenNA);
+        RComplexVector ret = RDataFactory.createComplexVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
         if (preserveAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
@@ -259,6 +268,10 @@ public abstract class CastComplexNode extends CastBaseNode {
         return CastComplexNodeGen.create(true, true, true);
     }
 
+    public static CastComplexNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastComplexNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastComplexNode createNonPreserving() {
         return CastComplexNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
index 86b4afa0308aa0ee8ff456edba298987dab7a23c..6e1b66b74024f6c999d8c11e844bd43ffdb56519 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
@@ -42,8 +43,16 @@ public abstract class CastDoubleBaseNode extends CastBaseNode {
     protected final NAProfile naProfile = NAProfile.create();
     protected final BranchProfile warningBranch = BranchProfile.create();
 
+    protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
+        super(preserveNames, preserveDimensions, preserveAttributes, messageCallObj);
+    }
+
     protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
@@ -86,7 +95,7 @@ public abstract class CastDoubleBaseNode extends CastBaseNode {
         double result = naCheck.convertComplexToDouble(operand, false);
         if (operand.getImaginaryPart() != 0.0) {
             warningBranch.enter();
-            RError.warning(this, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            RError.warning(messageCallObj, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
         }
         return result;
     }
@@ -106,7 +115,7 @@ public abstract class CastDoubleBaseNode extends CastBaseNode {
         double result = RRuntime.string2doubleNoCheck(operand);
         if (RRuntime.isNA(result)) {
             warningBranch.enter();
-            RError.warning(this, RError.Message.NA_INTRODUCED_COERCION);
+            RError.warning(messageCallObj, RError.Message.NA_INTRODUCED_COERCION);
         }
         return result;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
index 497b3d09277ed57c7bac6b5e1062a25c30c2a2ac..d937c07eef513dd28ae555162996c52622b1a445 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java
@@ -43,11 +43,20 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 public abstract class CastDoubleNode extends CastDoubleBaseNode {
 
     protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    }
+
+    protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallerObj) {
+        super(preserveNames, preserveDimensions, preserveAttributes, messageCallerObj);
     }
 
     @Child private CastDoubleNode recursiveCastDouble;
@@ -117,7 +126,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
             ddata[i] = doubleValue;
         }
         if (warning) {
-            RError.warning(this, RError.Message.NA_INTRODUCED_COERCION);
+            RError.warning(messageCallObj, RError.Message.NA_INTRODUCED_COERCION);
         }
         RDoubleVector ret = RDataFactory.createDoubleVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand));
         preserveDimensionNames(operand, ret);
@@ -141,7 +150,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
         }
         if (warning) {
             warningBranch.enter();
-            RError.warning(this, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            RError.warning(messageCallObj, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
         }
         return vectorCopy(operand, ddata, naCheck.neverSeenNA());
     }
@@ -206,6 +215,10 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode {
         return CastDoubleNodeGen.create(true, true, true);
     }
 
+    public static CastDoubleNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastDoubleNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastDoubleNode createNonPreserving() {
         return CastDoubleNodeGen.create(false, false, false);
     }
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 1178f3762ee7743577fe611918c14242c8f9592d..a5a4c01397428aa1bb6bb6e64d196c5e6f001906 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,11 @@ public abstract class CastExpressionNode extends CastBaseNode {
     public abstract Object executeExpression(Object o);
 
     protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
@@ -104,6 +108,11 @@ public abstract class CastExpressionNode extends CastBaseNode {
         return RDataFactory.createExpression(new Object[]{obj});
     }
 
+    public static CastExpressionNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        // RFFI coercion to list unlike others does not preserve names it seems
+        return CastExpressionNodeGen.create(false, false, false, true);
+    }
+
     public static CastExpressionNode createNonPreserving() {
         return CastExpressionNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
index 9f715e3836e42e393e5f342e825b9f9dd7e6fa3a..5a26f6d19895e8c6f35c4d243008cbc6b69d98e9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public abstract class CastIntegerBaseNode extends CastBaseNode {
@@ -44,7 +45,15 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
     @Child private CastIntegerNode recursiveCastInteger;
 
     protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    }
+
+    protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
+        super(preserveNames, preserveDimensions, preserveAttributes, messageCallObj);
     }
 
     @Override
@@ -55,7 +64,7 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
     protected Object castIntegerRecursive(Object o) {
         if (recursiveCastInteger == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            recursiveCastInteger = insert(CastIntegerNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes()));
+            recursiveCastInteger = insert(CastIntegerNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes(), messageCallObj));
         }
         return recursiveCastInteger.executeInt(o);
     }
@@ -87,7 +96,7 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
         int result = naCheck.convertComplexToInt(operand, false);
         if (operand.getImaginaryPart() != 0.0) {
             warningBranch.enter();
-            RError.warning(this, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            RError.warning(messageCallObj, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
         }
         return result;
     }
@@ -102,7 +111,7 @@ public abstract class CastIntegerBaseNode extends CastBaseNode {
         int result = RRuntime.string2intNoCheck(operand);
         if (RRuntime.isNA(result)) {
             warningBranch.enter();
-            RError.warning(this, RError.Message.NA_INTRODUCED_COERCION);
+            RError.warning(messageCallObj, RError.Message.NA_INTRODUCED_COERCION);
         }
         return result;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
index 28966f1ed7f7e23a34f530cad207887c528ec2fd..b0310c602bddc67547b37ceca490cbd62324916d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java
@@ -42,6 +42,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
 public abstract class CastIntegerNode extends CastIntegerBaseNode {
@@ -49,7 +50,15 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
     private final NAProfile naProfile = NAProfile.create();
 
     protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    }
+
+    protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
+        super(preserveNames, preserveDimensions, preserveAttributes, messageCallObj);
     }
 
     public abstract Object executeInt(int o);
@@ -118,7 +127,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
         }
         if (warning) {
             warningBranch.enter();
-            RError.warning(this, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
+            RError.warning(messageCallObj, RError.Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION);
         }
         return vectorCopy(operand, idata, naCheck.neverSeenNA());
     }
@@ -149,7 +158,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
             idata[i] = intValue;
         }
         if (warning) {
-            RError.warning(this, RError.Message.NA_INTRODUCED_COERCION);
+            RError.warning(messageCallObj, RError.Message.NA_INTRODUCED_COERCION);
         }
         return vectorCopy(operand, idata, !seenNA);
     }
@@ -221,14 +230,18 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode {
     }
 
     public static CastIntegerNode create() {
-        return CastIntegerNodeGen.create(true, true, true);
+        return CastIntegerNodeGen.create(true, true, true, null);
+    }
+
+    public static CastIntegerNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastIntegerNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
     }
 
     public static CastIntegerNode createNonPreserving() {
-        return CastIntegerNodeGen.create(false, false, false);
+        return CastIntegerNodeGen.create(false, false, false, null);
     }
 
     public static CastIntegerNode createPreserveNames() {
-        return CastIntegerNodeGen.create(false, false, false);
+        return CastIntegerNodeGen.create(false, false, false, null);
     }
 }
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 606b54d966886466339e13999070d035d9622b8c..1fc21b1956a3090baa9154e67dd895db82e8752f 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,7 +52,11 @@ public abstract class CastListNode extends CastBaseNode {
     public abstract RList executeList(Object o);
 
     protected CastListNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastListNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
@@ -143,4 +147,8 @@ public abstract class CastListNode extends CastBaseNode {
     public static CastListNode create() {
         return CastListNodeGen.create(true, true, true);
     }
+
+    public static CastListNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastListNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
index 03ea9e3eb653978486ba62171af92fc0b7b962b2..94f484b2fcb70f5c38f0cf120146a5e8d0db7066 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RRaw;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public abstract class CastLogicalBaseNode extends CastBaseNode {
@@ -34,7 +35,15 @@ public abstract class CastLogicalBaseNode extends CastBaseNode {
     protected final NACheck naCheck = NACheck.create();
 
     protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
+    }
+
+    protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
+        super(preserveNames, preserveDimensions, preserveAttributes, messageCallObj);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
index e104daf67ce2727daeda1dc5e8cc1c23a6febb88..6f15ddd3fc0adfaf0925225098145b3806ab1b5b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,7 @@ 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.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
 public abstract class CastLogicalNode extends CastLogicalBaseNode {
@@ -50,8 +51,16 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
     @Child private CastLogicalNode recursiveCastLogical;
     @Child private InheritsCheckNode inheritsFactorCheck;
 
+    protected CastLogicalNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, RBaseNode messageCallObj) {
+        super(preserveNames, preserveDimensions, preserveAttributes, messageCallObj);
+    }
+
     protected CastLogicalNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastLogicalNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     protected Object castLogicalRecursive(Object o) {
@@ -171,7 +180,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
                 }
             }
         }
-        RLogicalVector ret = RDataFactory.createLogicalVector(result, !seenNA);
+        RLogicalVector ret = RDataFactory.createLogicalVector(result, !seenNA, getPreservedDimensions(list), getPreservedNames(list));
         if (preserveAttributes()) {
             ret.copyRegAttributesFrom(list);
         }
@@ -192,6 +201,10 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode {
         return CastLogicalNodeGen.create(true, true, true);
     }
 
+    public static CastLogicalNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastLogicalNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastLogicalNode createNonPreserving() {
         return CastLogicalNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
index 5ef5ca20530477fdd9cb099ffc0bf2b58f33e485..9471d88d7a054c98afd9c2a79edc12bb6cc5b4b3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java
@@ -51,7 +51,11 @@ public abstract class CastRawNode extends CastBaseNode {
     private final BranchProfile warningBranch = BranchProfile.create();
 
     protected CastRawNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastRawNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Child private CastRawNode recursiveCastRaw;
@@ -143,6 +147,7 @@ public abstract class CastRawNode extends CastBaseNode {
         if (intRawValue != intValue) {
             warningBranch.enter();
             RError.warning(this, RError.Message.OUT_OF_RANGE);
+            return RRaw.valueOf((byte) 0);
         }
         return RRaw.valueOf((byte) intRawValue);
     }
@@ -223,7 +228,7 @@ public abstract class CastRawNode extends CastBaseNode {
                 if (intValue != intRawValue) {
                     warningBranch.enter();
                     outOfRangeWarning = true;
-                    intRawValue = 0;
+                    intValue = 0;
                 }
             }
             bdata[i] = (byte) intValue;
@@ -294,13 +299,21 @@ public abstract class CastRawNode extends CastBaseNode {
     @Specialization
     protected RRawVector doList(RAbstractListVector value) {
         int length = value.getLength();
-        RRawVector result = RDataFactory.createRawVector(length);
+        byte[] data = new byte[length];
         for (int i = 0; i < length; i++) {
-            result.updateDataAt(i, (RRaw) castRawRecursive(value.getDataAt(i)));
+            data[i] = ((RRaw) castRawRecursive(value.getDataAt(i))).getValue();
+        }
+        RRawVector result = RDataFactory.createRawVector(data, getPreservedDimensions(value), getPreservedNames(value));
+        if (preserveAttributes()) {
+            result.copyRegAttributesFrom(value);
         }
         return result;
     }
 
+    public static CastRawNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastRawNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastRawNode createNonPreserving() {
         return CastRawNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
index e5d9f51ef3fab718a57ff9e386fefb80704bdec6..8d3a0456e360fb32c4cb5eb2be2bc1a3a4a8bbea 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,11 @@ public abstract class CastStringBaseNode extends CastBaseNode {
     @Child private ToStringNode toString = ToStringNodeGen.create();
 
     protected CastStringBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastStringBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java
index 2bdf51e02a89fd602aa48fa584edbf64fcb68f59..a59b45866a9f896aba4c630d879592f5af370bc3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,11 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 public abstract class CastStringNode extends CastStringBaseNode {
 
     protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     public abstract Object executeString(int o);
@@ -85,6 +89,10 @@ public abstract class CastStringNode extends CastStringBaseNode {
         return CastStringNodeGen.create(true, true, true);
     }
 
+    public static CastStringNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastStringNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastStringNode createNonPreserving() {
         return CastStringNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
index 58cd32ecd1419a22a1b37836b1c71025602e487f..31b0fea74e35ffce8cef8529677f9387887efbae 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,21 +25,28 @@ package com.oracle.truffle.r.nodes.unary;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 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.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public abstract class CastSymbolNode extends CastBaseNode {
 
     @Child private ToStringNode toString = ToStringNodeGen.create();
 
     protected CastSymbolNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastSymbolNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
@@ -85,32 +92,55 @@ public abstract class CastSymbolNode extends CastBaseNode {
         return RDataFactory.createSymbolInterned(value);
     }
 
-    @Specialization
+    @Specialization(guards = "value.getLength() > 0")
     protected RSymbol doStringVector(RStringVector value) {
         // Only element 0 interpreted
         return doString(value.getDataAt(0));
     }
 
-    @Specialization
+    @Specialization(guards = "value.getLength() > 0")
     protected RSymbol doIntegerVector(RIntVector value) {
         return doInteger(value.getDataAt(0));
     }
 
-    @Specialization
+    @Specialization(guards = "value.getLength() > 0")
     protected RSymbol doDoubleVector(RDoubleVector value) {
         return doDouble(value.getDataAt(0));
     }
 
-    @Specialization
+    @Specialization(guards = "value.getLength() > 0")
     protected RSymbol doLogicalVector(RLogicalVector value) {
         return doLogical(value.getDataAt(0));
     }
 
+    @Specialization(guards = "vector.getLength() == 0")
+    @TruffleBoundary
+    protected RSymbol doEmptyVector(RAbstractVector vector) {
+        if (vector instanceof RList) {
+            throw RError.error(this, RError.Message.INVALID_TYPE_LENGTH, "symbol", 0);
+        } else {
+            throw RError.error(this, Message.INVALID_DATA_OF_TYPE_TOO_SHORT, vector.getRType().getName(), 0);
+        }
+    }
+
     @TruffleBoundary
     private static RSymbol asSymbol(String s) {
         return RDataFactory.createSymbolInterned(s);
     }
 
+    @Override
+    protected Object doOtherRFFI(Object mappedValue) {
+        if (mappedValue instanceof RList) {
+            // to be compatible with GnuR
+            throw RError.error(RError.NO_CALLER, Message.INVALID_TYPE_LENGTH, "symbol", ((RList) mappedValue).getLength());
+        }
+        return super.doOtherRFFI(mappedValue);
+    }
+
+    public static CastSymbolNode createForRFFI(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
+        return CastSymbolNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, true);
+    }
+
     public static CastSymbolNode createNonPreserving() {
         return CastSymbolNodeGen.create(false, false, false);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
index 92608cf7e342cce9085cf9b329b841ccb42fd2e3..790a649b001709dd8904deb6888618f7d3e492fe 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,11 @@ public abstract class CastToAttributableNode extends CastBaseNode {
     public abstract Object executeObject(Object value);
 
     protected CastToAttributableNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastToAttributableNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
index 6446fb5726c4ac08915478f269ab4f1d5c101378..383e4adb83981d2687459d79f18864669741aa4e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,11 @@ public abstract class CastToContainerNode extends CastBaseNode {
     public abstract Object executeObject(Object value);
 
     protected CastToContainerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) {
-        super(preserveNames, preserveDimensions, preserveAttributes);
+        this(preserveNames, preserveDimensions, preserveAttributes, false);
+    }
+
+    protected CastToContainerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean forRFFI) {
+        super(preserveNames, preserveDimensions, preserveAttributes, forRFFI);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java
index f4f299fa5e6f591b38bbb5bed7accdbe771d427c..f645d23f52d00e855f51b0d7c639e3258d8755b5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToVectorNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.dsl.NodeField;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -30,14 +29,21 @@ import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
-@NodeField(name = "preserveNonVector", type = boolean.class)
 public abstract class CastToVectorNode extends CastNode {
 
-    public abstract boolean isPreserveNonVector();
+    private final boolean preserveNonVector;
+
+    protected CastToVectorNode(boolean preserveNonVector) {
+        this.preserveNonVector = preserveNonVector;
+    }
+
+    public final boolean isPreserveNonVector() {
+        return preserveNonVector;
+    }
 
     @Specialization
     protected Object castNull(@SuppressWarnings("unused") RNull rnull) {
-        if (isPreserveNonVector()) {
+        if (preserveNonVector) {
             return RNull.instance;
         } else {
             return RDataFactory.createList();
@@ -46,7 +52,7 @@ public abstract class CastToVectorNode extends CastNode {
 
     @Specialization
     protected Object castMissing(@SuppressWarnings("unused") RMissing missing) {
-        if (isPreserveNonVector()) {
+        if (preserveNonVector) {
             return RMissing.instance;
         } else {
             return RDataFactory.createList();
@@ -55,7 +61,7 @@ public abstract class CastToVectorNode extends CastNode {
 
     @Specialization
     protected Object castFunction(RFunction f) {
-        if (isPreserveNonVector()) {
+        if (preserveNonVector) {
             return f;
         } else {
             return RDataFactory.createList();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNode.java
index c6c19f8f13d4a23dd5a3a3cefefc2ce7271cec9b..081b1bc06a596aea8bd5fd1900d4cbbb34aaa99a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConditionalMapNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.ControlFlowException;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.ArgumentFilter;
 import com.oracle.truffle.r.runtime.data.RMissing;
@@ -34,23 +35,29 @@ public abstract class ConditionalMapNode extends CastNode {
     private final ConditionProfile conditionProfile = ConditionProfile.createBinaryProfile();
     private final boolean resultForNull;
     private final boolean resultForMissing;
+    private final boolean returns;
 
     @Child private CastNode trueBranch;
     @Child private CastNode falseBranch;
 
     protected ConditionalMapNode(ArgumentFilter<?, ?> argFilter, CastNode trueBranch, CastNode falseBranch, boolean resultForNull,
-                    boolean resultForMissing) {
+                    boolean resultForMissing, boolean returns) {
         this.argFilter = argFilter;
         this.trueBranch = trueBranch;
         this.falseBranch = falseBranch;
         this.resultForNull = resultForNull;
         this.resultForMissing = resultForMissing;
+        this.returns = returns;
     }
 
     public static ConditionalMapNode create(ArgumentFilter<?, ?> argFilter, CastNode trueBranch,
                     CastNode falseBranch, boolean resultForNull,
-                    boolean resultForMissing) {
-        return ConditionalMapNodeGen.create(argFilter, trueBranch, falseBranch, resultForNull, resultForMissing);
+                    boolean resultForMissing, boolean returns) {
+        return ConditionalMapNodeGen.create(argFilter, trueBranch, falseBranch, resultForNull, resultForMissing, returns);
+    }
+
+    public boolean isReturns() {
+        return returns;
     }
 
     public ArgumentFilter<?, ?> getFilter() {
@@ -68,7 +75,12 @@ public abstract class ConditionalMapNode extends CastNode {
     @Specialization
     protected Object executeNull(RNull x) {
         if (resultForNull) {
-            return trueBranch == null ? x : trueBranch.execute(x);
+            Object result = trueBranch == null ? x : trueBranch.execute(x);
+            if (returns) {
+                throw new PipelineReturnException(result);
+            } else {
+                return result;
+            }
         } else {
             return falseBranch == null ? x : falseBranch.execute(x);
         }
@@ -77,7 +89,12 @@ public abstract class ConditionalMapNode extends CastNode {
     @Specialization
     protected Object executeMissing(RMissing x) {
         if (resultForMissing) {
-            return trueBranch == null ? x : trueBranch.execute(x);
+            Object result = trueBranch == null ? x : trueBranch.execute(x);
+            if (returns) {
+                throw new PipelineReturnException(result);
+            } else {
+                return result;
+            }
         } else {
             return falseBranch == null ? x : falseBranch.execute(x);
         }
@@ -91,9 +108,28 @@ public abstract class ConditionalMapNode extends CastNode {
     @SuppressWarnings("unchecked")
     protected Object executeRest(Object x) {
         if (conditionProfile.profile(((ArgumentFilter<Object, Object>) argFilter).test(x))) {
-            return trueBranch == null ? x : trueBranch.execute(x);
+            Object result = trueBranch == null ? x : trueBranch.execute(x);
+            if (returns) {
+                throw new PipelineReturnException(result);
+            } else {
+                return result;
+            }
         } else {
             return falseBranch == null ? x : falseBranch.execute(x);
         }
     }
+
+    @SuppressWarnings("serial")
+    public final class PipelineReturnException extends ControlFlowException {
+
+        private final Object result;
+
+        public PipelineReturnException(Object result) {
+            this.result = result;
+        }
+
+        public Object getResult() {
+            return result;
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java
index 82b940252a7b6c985cb83f8fa8c35a8b31c1c878..9a4fe5e0466288eefe2b0e64e086afb1beebc916 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.unary;
 
 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.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
@@ -44,7 +43,7 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
-@NodeChildren({@NodeChild("operand")})
+@NodeChild("operand")
 public abstract class ConvertBooleanNode extends RNode {
 
     private final NAProfile naProfile = NAProfile.create();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstBooleanNode.java
index 6a9e9306fce88892407eada830dfde694a26588e..4a0c825550185fa9cde0d5625784d4db33747226 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstBooleanNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstBooleanNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -77,7 +77,7 @@ public abstract class FirstBooleanNode extends CastNode {
         }
     }
 
-    @Specialization(contains = "firstScalar")
+    @Specialization(replaces = "firstScalar")
     protected boolean firstVector(RAbstractLogicalVector argument) {
         checkLength(argument);
         return firstScalar(argument.getDataAt(0));
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstIntNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstIntNode.java
index 357f8d27291600852c99af6ce006d8cda16355a0..54d04e8c92348567801b540b933141b02fc5eb73 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstIntNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstIntNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,25 +22,26 @@
  */
 package com.oracle.truffle.r.nodes.unary;
 
-import com.oracle.truffle.api.dsl.NodeField;
-import com.oracle.truffle.api.dsl.NodeFields;
 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.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
-@NodeFields({@NodeField(name = "emptyError", type = RError.Message.class), @NodeField(name = "sizeWarning", type = RError.Message.class), @NodeField(name = "argumentName", type = String.class),
-                @NodeField(name = "defaultValue", type = int.class)})
 public abstract class FirstIntNode extends CastNode {
 
-    protected abstract RError.Message getEmptyError();
+    private final RError.Message emptyError;
+    private final RError.Message sizeWarning;
+    private final String argumentName;
+    private final int defaultValue;
 
-    protected abstract RError.Message getSizeWarning();
-
-    protected abstract String getArgumentName();
-
-    protected abstract int getDefaultValue();
+    protected FirstIntNode(Message emptyError, Message sizeWarning, String argumentName, int defaultValue) {
+        this.emptyError = emptyError;
+        this.sizeWarning = sizeWarning;
+        this.argumentName = argumentName;
+        this.defaultValue = defaultValue;
+    }
 
     public abstract int executeInt(Object value);
 
@@ -52,17 +53,17 @@ public abstract class FirstIntNode extends CastNode {
         return argument;
     }
 
-    @Specialization(contains = "firstScalar")
+    @Specialization(replaces = "firstScalar")
     protected int firstVector(RAbstractIntVector argument) {
         if (!lengthOneProfile.profile(argument.getLength() == 1)) {
-            if (getSizeWarning() != null) {
-                RError.warning(this, getSizeWarning(), getArgumentName());
+            if (sizeWarning != null) {
+                RError.warning(this, sizeWarning, argumentName);
                 if (argument.getLength() == 0) {
-                    return getDefaultValue();
+                    return defaultValue;
                 }
-            } else if (getEmptyError() != null && argument.getLength() == 0) {
+            } else if (emptyError != null && argument.getLength() == 0) {
                 errorProfile.enter();
-                throw RError.error(this, getEmptyError(), getArgumentName());
+                throw RError.error(this, emptyError, argumentName);
             }
         }
         return argument.getDataAt(0);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstStringNode.java
index 1216575a76df1e8ae46b771f264829b5b7aed623..a1672bbea11b297a6b12a90dc584590e27cb9335 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/FirstStringNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,20 +23,22 @@
 package com.oracle.truffle.r.nodes.unary;
 
 import com.oracle.truffle.api.dsl.Fallback;
-import com.oracle.truffle.api.dsl.NodeField;
-import com.oracle.truffle.api.dsl.NodeFields;
 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.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
-@NodeFields({@NodeField(name = "emptyError", type = RError.Message.class), @NodeField(name = "argumentName", type = String.class)})
 public abstract class FirstStringNode extends CastNode {
 
-    protected abstract RError.Message getEmptyError();
+    private final RError.Message emptyError;
+    private final String argumentName;
 
-    protected abstract String getArgumentName();
+    protected FirstStringNode(Message emptyError, String argumentName) {
+        this.emptyError = emptyError;
+        this.argumentName = argumentName;
+    }
 
     private final ConditionProfile lengthOneProfile = ConditionProfile.createBinaryProfile();
     private final BranchProfile errorProfile = BranchProfile.create();
@@ -50,18 +52,18 @@ public abstract class FirstStringNode extends CastNode {
         return argument;
     }
 
-    @Specialization(contains = "firstScalar")
+    @Specialization(replaces = "firstScalar")
     protected String firstVector(RAbstractStringVector argument) {
         if (!lengthOneProfile.profile(argument.getLength() == 1)) {
             errorProfile.enter();
-            throw RError.error(RError.SHOW_CALLER, getEmptyError(), getArgumentName());
+            throw RError.error(RError.SHOW_CALLER, emptyError, argumentName);
         }
         return argument.getDataAt(0);
     }
 
     @Fallback
     protected String firstVectorFallback(@SuppressWarnings("unused") Object argument) {
-        throw RError.error(RError.SHOW_CALLER, getEmptyError(), getArgumentName());
+        throw RError.error(RError.SHOW_CALLER, emptyError, argumentName);
     }
 
     public static FirstStringNode createWithError(RError.Message emptyError, String argumentName) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
index 4b38a39d77b5b0ee36e2a2b5036320f13001c9cd..358b1b3ce467b0eea5a5d1087d1f007dfc0fbdad 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/TypeofNode.java
@@ -29,7 +29,6 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 
-@SuppressWarnings("unused")
 public abstract class TypeofNode extends UnaryNode {
 
     protected static final int NUMBER_OF_CACHED_CLASSES = 5;
@@ -38,27 +37,27 @@ public abstract class TypeofNode extends UnaryNode {
     public abstract RType execute(Object x);
 
     @Specialization
-    protected static RType doLogical(byte x) {
+    protected static RType doLogical(@SuppressWarnings("unused") byte x) {
         return RType.Logical;
     }
 
     @Specialization
-    protected static RType doInt(int s) {
+    protected static RType doInt(@SuppressWarnings("unused") int s) {
         return RType.Integer;
     }
 
     @Specialization
-    protected static RType doDouble(double x) {
+    protected static RType doDouble(@SuppressWarnings("unused") double x) {
         return RType.Double;
     }
 
     @Specialization
-    protected static RType doString(String x) {
+    protected static RType doString(@SuppressWarnings("unused") String x) {
         return RType.Character;
     }
 
     @Specialization
-    protected static RType doMissing(RMissing x) {
+    protected static RType doMissing(@SuppressWarnings("unused") RMissing x) {
         return RType.Missing;
     }
 
@@ -77,7 +76,7 @@ public abstract class TypeofNode extends UnaryNode {
         }
     }
 
-    @Specialization(contains = {"doCachedTyped"})
+    @Specialization(replaces = {"doCachedTyped"})
     protected static RType doGenericTyped(RTypedValue operand) {
         return operand.getRType();
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
index 175f43258d4a942db5075f7223814e49b0e46e36..bd584cf1bdc35a4d19f814e6aa219aa6b2d3bb1c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java
@@ -94,7 +94,7 @@ public abstract class UnaryArithmeticNode extends UnaryNode {
         return value instanceof RAbstractIntVector || value instanceof RAbstractDoubleVector || value instanceof RAbstractComplexVector || value instanceof RAbstractLogicalVector;
     }
 
-    @Specialization(contains = "doCached", guards = {"isNumericVector(operand)"})
+    @Specialization(replaces = "doCached", guards = {"isNumericVector(operand)"})
     @TruffleBoundary
     protected Object doGeneric(Object operand,
                     @Cached("unary.createOperation()") UnaryArithmetic arithmetic,
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java
index 06562ff9dc4a0951c5010efda82e303d2368d1a6..2d3092d235814b373c0e89b9d5e45d89692e778a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.unary;
 
 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.dsl.TypeSystemReference;
 import com.oracle.truffle.api.profiles.BranchProfile;
@@ -47,7 +48,12 @@ import com.oracle.truffle.r.runtime.ops.BinaryArithmeticFactory;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 /**
- * TODO: handle "finite" parameter correctly.
+ * This node is used at several places, but only 'range' actually uses the 'finite' parameter,
+ * others should typically use {@code false} as its value. The 'finite' parameter is not handled
+ * consistently in GnuR: the documentation reads ‘finite = TRUE’ _includes_ ‘na.rm = TRUE’, but this
+ * only applies to some types (e.g. double or integer), for other types 'finite' seems to be ignored
+ * (e.g. logical). The only situation where semantics of finite is different to na.rm is double
+ * values: na.rm removes NA and NaN, but not -/+Inf.
  */
 @TypeSystemReference(RTypes.class)
 public abstract class UnaryArithmeticReduceNode extends RBaseNode {
@@ -125,16 +131,21 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected double doDouble(double operand, boolean naRm, @SuppressWarnings("unused") boolean finite) {
+    protected double doDouble(double operand, boolean naRm, boolean finite,
+                    @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) {
         na.enable(operand);
-        if (naRmProfile.profile(naRm)) {
-            if (na.check(operand)) {
+        if (naRmProfile.profile(naRm || finite)) {
+            boolean profiledFinite = finiteProfile.profile(finite);
+            if (na.checkNAorNaN(operand) || (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(operand)))) {
+                // the only value we have should be removed...
                 emptyWarning();
                 return semantics.getIntStart();
             } else {
                 return operand;
             }
         } else {
+            // since !naRm and !finite, NaN or +/-Inf can be valid results
             return na.check(operand) ? RRuntime.DOUBLE_NA : operand;
         }
     }
@@ -204,9 +215,9 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected int doIntVector(RIntVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite) {
+    protected int doIntVector(RIntVector operand, boolean naRm, boolean finite) {
         RBaseNode.reportWork(this, operand.getLength());
-        boolean profiledNaRm = naRmProfile.profile(naRm);
+        boolean profiledNaRm = naRmProfile.profile(naRm || finite);
         int result = semantics.getIntStart();
         na.enable(operand);
         int opCount = 0;
@@ -235,24 +246,33 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected double doDoubleVector(RDoubleVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite) {
+    protected double doDoubleVector(RDoubleVector operand, boolean naRm, boolean finite,
+                    @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) {
         RBaseNode.reportWork(this, operand.getLength());
-        boolean profiledNaRm = naRmProfile.profile(naRm);
+        boolean profiledNaRm = naRmProfile.profile(naRm || finite);
+        boolean profiledFinite = finiteProfile.profile(finite);
         double result = semantics.getDoubleStart();
         na.enable(operand);
         int opCount = 0;
         double[] data = operand.getDataWithoutCopying();
         for (int i = 0; i < operand.getLength(); i++) {
             double d = data[i];
-            if (na.check(d)) {
+            if (na.checkNAorNaN(d)) {
                 if (profiledNaRm) {
-                    continue;
-                } else {
+                    continue;   // ignore NA/NaN
+                } else if (na.check(d)) {
+                    // NA produces NA directly, but NaN should be handled by arithmetics.op to
+                    // produce NaN. We cannot directly return NaN because if we encounter NA later
+                    // on, we should return NA not NaN
                     return RRuntime.DOUBLE_NA;
                 }
-            } else {
-                result = arithmetic.op(result, d);
+            } else if (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(d))) {
+                // ignore -/+Inf if 'infinite == TRUE'
+                continue;
             }
+
+            result = arithmetic.op(result, d);
             opCount++;
         }
         if (opCount == 0) {
@@ -327,10 +347,10 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected RComplex doComplexVector(RComplexVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite) {
+    protected RComplex doComplexVector(RComplexVector operand, boolean naRm, boolean finite) {
         RBaseNode.reportWork(this, operand.getLength());
         if (semantics.supportComplex) {
-            boolean profiledNaRm = naRmProfile.profile(naRm);
+            boolean profiledNaRm = naRmProfile.profile(naRm || finite);
             RComplex result = RRuntime.double2complex(semantics.getDoubleStart());
             int opCount = 0;
             na.enable(operand);
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 a1e52ad1f1ecc8bc4851017311d51e9009f3b226..1d28787a2641fea4c12d0c5b7e20bda88bb6698a 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
@@ -55,6 +55,10 @@ public abstract class UnaryNotNode extends RBuiltinNode {
     private final NAProfile naProfile = NAProfile.create();
     private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile();
 
+    static {
+        Casts.noCasts(UnaryNotNode.class);
+    }
+
     private static byte not(byte value) {
         return (value == RRuntime.LOGICAL_TRUE ? RRuntime.LOGICAL_FALSE : RRuntime.LOGICAL_TRUE);
     }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/Load_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/Load_RFFIFactory.java
deleted file mode 100644
index 5450aec0a2854787bd2fcd81ca70db4366e1c6fd..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/Load_RFFIFactory.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.Utils;
-
-/**
- * Selects a particular subclass of {@link RFFIFactory}. Specification is based on system property
- * {@value #FACTORY_CLASS_PROPERTY}. Current default is a JNI-based implementation.
- */
-public class Load_RFFIFactory {
-    private static final String FACTORY_CLASS_PROPERTY = "fastr.ffi.factory.class";
-    private static final String DEFAULT_FACTORY_CLASS = "com.oracle.truffle.r.runtime.ffi.jni.JNI_RFFIFactory";
-
-    /**
-     * Singleton instance of the factory. Typically initialized at runtime but may be initialized
-     * during image build in an AOT VM, in which case {@code runtime} will be {@code false}.
-     */
-    private static RFFIFactory instance;
-
-    public static RFFIFactory initialize(boolean runtime) {
-        if (instance == null) {
-            String prop = System.getProperty(FACTORY_CLASS_PROPERTY);
-            try {
-                if (prop == null) {
-                    prop = DEFAULT_FACTORY_CLASS;
-                }
-                instance = (RFFIFactory) Class.forName(prop).newInstance();
-                RFFIFactory.setRFFIFactory(instance);
-            } catch (Exception ex) {
-                throw Utils.rSuicide("Failed to instantiate class: " + prop + ": " + ex);
-            }
-        }
-        instance.initialize(runtime);
-        return instance;
-    }
-}
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 77628a0b8d8b06eba9a99ed0144e89924e0f12a6..be05015ada910b1c72a7a596469ba54285284f47 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.ffi;
 
 import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.TempPathName;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -32,7 +33,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public enum RFFIVariables {
     R_Home(REnvVars.rHome()),
-    R_TempDir(null), // Set later with setTmpDir
+    R_TempDir(null), // Set later
     R_NilValue(RNull.instance),
     R_UnboundValue(RUnboundValue.instance),
     R_MissingArg(RMissing.instance),
@@ -76,10 +77,11 @@ public enum RFFIVariables {
     R_NegInf(Double.NEGATIVE_INFINITY),
     R_NaReal(RRuntime.DOUBLE_NA),
     R_NaInt(RRuntime.INT_NA),
-    R_BlankString(RDataFactory.createStringVectorFromScalar("")),
-    R_TrueValue(RRuntime.LOGICAL_TRUE),
-    R_FalseValue(RRuntime.LOGICAL_FALSE),
-    R_LogicalNAValue(RRuntime.LOGICAL_NA);
+    R_BlankString(CharSXPWrapper.create("")),
+    R_BlankScalarString(RDataFactory.createStringVectorFromScalar("")),
+    R_BaseSymbol(RDataFactory.createSymbol("base")),
+    R_NamespaceEnvSymbol(RDataFactory.createSymbol(".__NAMESPACE__.")),
+    R_RestartToken(null);
 
     private Object value;
 
@@ -91,7 +93,12 @@ public enum RFFIVariables {
         return value;
     }
 
-    public static void setTempDir(String tempDir) {
-        R_TempDir.value = tempDir;
+    /**
+     * Sets {@link #R_TempDir} for the initial context.
+     */
+    public static RFFIVariables[] initialize() {
+        R_TempDir.value = TempPathName.tempDirPath();
+        return values();
+
     }
 }
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 6161b0e4e724a3d1ddf555a888b9a41cf75a3858..8aad787c5526a3ef2f7f9b8bbb80790a34762857 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,66 +22,66 @@
  */
 package com.oracle.truffle.r.runtime.ffi.generic;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.GridRFFI;
-import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public class Generic_Grid implements GridRFFI {
-    private static class Generic_GridRFFINode extends GridRFFINode {
-        @Child private CallRFFI.CallRFFINode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode();
+    private static final String GRID = "grid";
 
-        private static final class GridProvider {
-            private static GridProvider grid;
-            private static DLL.SymbolHandle initGrid;
-            private static DLL.SymbolHandle killGrid;
+    private static class Generic_InitGridNode extends InitGridNode {
+        private static final String L_InitGrid = "L_initGrid";
+        @Child private CallRFFI.InvokeCallNode invokeCallNode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
+        @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
+        @CompilationFinal private NativeCallInfo initNativeCallInfo;
 
-            @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;
+        @Override
+        public Object execute(REnvironment gridEvalEnv) {
+            if (initNativeCallInfo == null) {
+                initNativeCallInfo = createNativeCallInfo(L_InitGrid, findSymbolNode);
             }
+            return invokeCallNode.execute(initNativeCallInfo, new Object[]{gridEvalEnv});
+        }
+    }
 
-            @SuppressWarnings("static-method")
-            long getInitGrid() {
-                return initGrid.asAddress();
-            }
+    private static class Generic_KillGridNode extends KillGridNode {
+        private static final String L_KillGrid = "L_killGrid";
+        @Child private CallRFFI.InvokeCallNode invokeCallNode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
+        @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
+        @CompilationFinal private NativeCallInfo killNativeCallInfo;
 
-            @SuppressWarnings("static-method")
-            long getKillGrid() {
-                return killGrid.asAddress();
+        @Override
+        public Object execute() {
+            if (killNativeCallInfo == null) {
+                killNativeCallInfo = createNativeCallInfo(L_KillGrid, findSymbolNode);
             }
+            return invokeCallNode.execute(killNativeCallInfo, new Object[0]);
         }
 
-        @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 killGrid() {
-            long killGrid = GridProvider.gridProvider().getKillGrid();
-            return callRFFINode.invokeCall(new NativeCallInfo("L_killGrid", new SymbolHandle(killGrid), DLL.findLibrary("grid")), new Object[0]);
-        }
+    private static NativeCallInfo createNativeCallInfo(String call, DLL.RFindSymbolNode findSymbolNode) {
+        DLLInfo dllInfo = DLL.findLibrary(GRID);
+        assert dllInfo != null;
+        SymbolHandle symbolHandle = findSymbolNode.execute(call, GRID, DLL.RegisteredNativeSymbol.any());
+        assert symbolHandle != DLL.SYMBOL_NOT_FOUND;
+        return new NativeCallInfo(call, symbolHandle, dllInfo);
     }
 
     @Override
-    public GridRFFINode createGridRFFINode() {
-        return new Generic_GridRFFINode();
+    public InitGridNode createInitGridNode() {
+        return new Generic_InitGridNode();
     }
+
+    @Override
+    public KillGridNode createKillGridNode() {
+        return new Generic_KillGridNode();
+    }
+
 }
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 6b8a93ca053a86a81ca62bbd16f8e73368633144..170f820fd28611c2b6d286f668ec8320198a6862 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,9 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.ffi.generic;
 
-import java.util.concurrent.Semaphore;
-
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.conn.RConnection;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
@@ -32,66 +30,47 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
 import com.oracle.truffle.r.runtime.ffi.DLL;
+import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
-import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.ToolsRFFI;
 
 public class Generic_Tools implements ToolsRFFI {
-    private static class Generic_ToolsRFFINode extends ToolsRFFINode {
-        @Child private CallRFFI.CallRFFINode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode();
-
-        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 ParseRdNode {
+        private static final String C_PARSE_RD = "C_parseRd";
+        private static final String TOOLS = "tools";
 
-            @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;
-            }
-
-            @SuppressWarnings("static-method")
-            long getParseRd() {
-                return parseRd.asAddress();
-            }
-        }
+        @Child private CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
+        @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
 
-        private static final Semaphore parseRdCritical = new Semaphore(1, false);
-        private NativeCallInfo nativeCallInfo;
+        @CompilationFinal private NativeCallInfo nativeCallInfo;
 
+        /**
+         * Invoke C implementation, N.B., code is not thread safe.
+         */
         @Override
-        public Object parseRd(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
+        public synchronized Object execute(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"));
+                    // lookup entry point (assert library is loaded)
+                    DLLInfo toolsDLLInfo = DLL.findLibrary(TOOLS);
+                    assert toolsDLLInfo != null;
+                    SymbolHandle symbolHandle = findSymbolNode.execute(C_PARSE_RD, TOOLS, DLL.RegisteredNativeSymbol.any());
+                    assert symbolHandle != DLL.SYMBOL_NOT_FOUND;
+                    nativeCallInfo = new NativeCallInfo(C_PARSE_RD, symbolHandle, toolsDLLInfo);
                 }
-                return callRFFINode.invokeCall(nativeCallInfo,
+                return callRFFINode.execute(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();
             }
         }
     }
 
     @Override
-    public ToolsRFFINode createToolsRFFINode() {
+    public ParseRdNode createParseRdNode() {
         return new Generic_ToolsRFFINode();
     }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNIUpCallsRFFIImpl.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNIUpCallsRFFIImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..233e055e8ed4414f744bc12200c1b25df822a6ae
--- /dev/null
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNIUpCallsRFFIImpl.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.ffi.jni;
+
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.guaranteeInstanceOf;
+
+import com.oracle.truffle.r.nodes.ffi.JavaUpCallsRFFIImpl;
+import com.oracle.truffle.r.runtime.RErrorHandling;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper;
+
+/**
+ * Some additional methods to support the native JNI side.
+ */
+public class JNIUpCallsRFFIImpl extends JavaUpCallsRFFIImpl {
+    // Checkstyle: stop method name check
+
+    /**
+     * Helper function for {@code R_TopLevelExec}, see {@link #R_ToplevelExec()}, called after C
+     * function returns.
+     */
+    public static void R_ToplevelExecRestoreErrorHandlerStacks(Object stacks) {
+        RErrorHandling.HandlerStacks handlerStacks = guaranteeInstanceOf(stacks, RErrorHandling.HandlerStacks.class);
+        RErrorHandling.restoreHandlerStacks(handlerStacks);
+    }
+
+    /**
+     * 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);
+        }
+    }
+
+    /**
+     * Called when a {@link CharSXPWrapper} is expected and not found.
+     */
+    public static void logNotCharSXPWrapper(Object x) {
+        System.out.println("object " + x);
+        System.out.println("class " + x.getClass());
+    }
+
+    @Override
+    public Object R_CHAR(Object x) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
+}
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Base.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Base.java
index 08c7928e005e53460b1df305a80ac1336a90e747..dac6e7af7654c4458feb204ba68ba39b6c8dd2ae 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Base.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Base.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,101 +25,132 @@ package com.oracle.truffle.r.runtime.ffi.jni;
 import java.io.IOException;
 import java.util.ArrayList;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 public class JNI_Base implements BaseRFFI {
-    @Override
-    public int getpid() {
-        return native_getpid();
-    }
-
-    @Override
-    public int setwd(String dir) {
-        return native_setwd(dir);
+    public static class JNI_GetpidNode extends GetpidNode {
+        @TruffleBoundary
+        @Override
+        public int execute() {
+            return native_getpid();
+        }
     }
 
-    @Override
-    public String getwd() {
-        byte[] buf = new byte[4096];
-        int rc = native_getwd(buf, buf.length);
-        if (rc == 0) {
-            return null;
-        } else {
-            int i = 0;
-            while (buf[i] != 0 && i < buf.length) {
-                i++;
+    public static class JNI_GetwdNode extends GetwdNode {
+        @TruffleBoundary
+        @Override
+        public String execute() {
+            byte[] buf = new byte[4096];
+            int rc = native_getwd(buf, buf.length);
+            if (rc == 0) {
+                return null;
+            } else {
+                int i = 0;
+                while (buf[i] != 0 && i < buf.length) {
+                    i++;
+                }
+                return new String(buf, 0, i);
             }
-            return new String(buf, 0, i);
         }
     }
 
-    private static final int EINVAL = 22;
+    public static class JNI_SetwdNode extends SetwdNode {
+        @TruffleBoundary
+        @Override
+        public int execute(String dir) {
+            return native_setwd(dir);
+        }
+    }
 
-    @Override
-    public String readlink(String path) throws IOException {
-        int[] errno = new int[]{0};
-        String s = native_readlink(path, errno);
-        if (s == null) {
-            if (errno[0] == EINVAL) {
-                // not a link
-            } else {
-                // some other error
-                throw new IOException("readlink failed: " + errno[0]);
+    public static class JNI_ReadlinkNode extends ReadlinkNode {
+        private static final int EINVAL = 22;
+
+        @TruffleBoundary
+        @Override
+        public String execute(String path) throws IOException {
+            int[] errno = new int[]{0};
+            String s = native_readlink(path, errno);
+            if (s == null) {
+                if (errno[0] == EINVAL) {
+                    // not a link
+                } else {
+                    // some other error
+                    throw new IOException("readlink failed: " + errno[0]);
+                }
             }
+            return s;
         }
-        return s;
     }
 
-    @Override
-    public String mkdtemp(String template) {
-        /*
-         * Not only must the (C) string end in XXXXXX it must also be null-terminated. Since it is
-         * modified by mkdtemp we must make a copy.
-         */
-        byte[] bytes = template.getBytes();
-        byte[] ztbytes = new byte[bytes.length + 1];
-        System.arraycopy(bytes, 0, ztbytes, 0, bytes.length);
-        ztbytes[bytes.length] = 0;
-        long result = native_mkdtemp(ztbytes);
-        if (result == 0) {
-            return null;
-        } else {
-            return new String(ztbytes, 0, bytes.length);
+    public static class JNI_MkdtempNode extends MkdtempNode {
+        @TruffleBoundary
+        @Override
+        public String execute(String template) {
+            /*
+             * Not only must the (C) string end in XXXXXX it must also be null-terminated. Since it
+             * is modified by mkdtemp we must make a copy.
+             */
+            byte[] bytes = template.getBytes();
+            byte[] ztbytes = new byte[bytes.length + 1];
+            System.arraycopy(bytes, 0, ztbytes, 0, bytes.length);
+            ztbytes[bytes.length] = 0;
+            long result = native_mkdtemp(ztbytes);
+            if (result == 0) {
+                return null;
+            } else {
+                return new String(ztbytes, 0, bytes.length);
+            }
         }
     }
 
-    @Override
-    public void mkdir(String dir, int mode) throws IOException {
-        int rc = native_mkdir(dir, mode);
-        if (rc != 0) {
-            throw new IOException("mkdir " + dir + " failed");
+    public static class JNI_MkdirNode extends MkdirNode {
+        @TruffleBoundary
+        @Override
+        public void execute(String dir, int mode) throws IOException {
+            int rc = native_mkdir(dir, mode);
+            if (rc != 0) {
+                throw new IOException("mkdir " + dir + " failed");
+            }
         }
     }
 
-    @Override
-    public int chmod(String path, int mode) {
-        return native_chmod(path, mode);
+    public static class JNI_ChmodNode extends ChmodNode {
+        @TruffleBoundary
+        @Override
+        public int execute(String path, int mode) {
+            return native_chmod(path, mode);
+        }
     }
 
-    @Override
-    public long strtol(String s, int base) throws IllegalArgumentException {
-        int[] errno = new int[]{0};
-        long result = native_strtol(s, base, errno);
-        if (errno[0] != 0) {
-            throw new IllegalArgumentException("strtol failure");
-        } else {
-            return result;
+    public static class JNI_StrolNode extends StrolNode {
+        @TruffleBoundary
+        @Override
+        public long execute(String s, int base) throws IllegalArgumentException {
+            int[] errno = new int[]{0};
+            long result = native_strtol(s, base, errno);
+            if (errno[0] != 0) {
+                throw new IllegalArgumentException("strtol failure");
+            } else {
+                return result;
+            }
         }
     }
 
-    @Override
-    public UtsName uname() {
-        return JNI_UtsName.get();
+    public static class JNI_UnameNode extends UnameNode {
+        @TruffleBoundary
+        @Override
+        public UtsName execute() {
+            return JNI_UtsName.get();
+        }
     }
 
-    @Override
-    public ArrayList<String> glob(String pattern) {
-        return JNI_Glob.glob(pattern);
+    public static class JNI_GlobNode extends GlobNode {
+        @TruffleBoundary
+        @Override
+        public ArrayList<String> glob(String pattern) {
+            return JNI_Glob.glob(pattern);
+        }
     }
 
     // Checkstyle: stop method name
@@ -139,4 +170,54 @@ public class JNI_Base implements BaseRFFI {
     private static native long native_strtol(String s, int base, int[] errno);
 
     private static native String native_readlink(String s, int[] errno);
+
+    @Override
+    public GetpidNode createGetpidNode() {
+        return new JNI_GetpidNode();
+    }
+
+    @Override
+    public GetwdNode createGetwdNode() {
+        return new JNI_GetwdNode();
+    }
+
+    @Override
+    public SetwdNode createSetwdNode() {
+        return new JNI_SetwdNode();
+    }
+
+    @Override
+    public MkdirNode createMkdirNode() {
+        return new JNI_MkdirNode();
+    }
+
+    @Override
+    public ReadlinkNode createReadlinkNode() {
+        return new JNI_ReadlinkNode();
+    }
+
+    @Override
+    public MkdtempNode createMkdtempNode() {
+        return new JNI_MkdtempNode();
+    }
+
+    @Override
+    public ChmodNode createChmodNode() {
+        return new JNI_ChmodNode();
+    }
+
+    @Override
+    public StrolNode createStrolNode() {
+        return new JNI_StrolNode();
+    }
+
+    @Override
+    public UnameNode createUnameNode() {
+        return new JNI_UnameNode();
+    }
+
+    @Override
+    public GlobNode createGlobNode() {
+        return new JNI_GlobNode();
+    }
 }
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 a4e26e084cb26a2b33636465fd06b613b18346ba..93311fa0b1a565cba34338c6cb1d354ed507a210 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_C.java
@@ -22,15 +22,15 @@
  */
 package com.oracle.truffle.r.runtime.ffi.jni;
 
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCall;
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceEnabled;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceDownCall;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceEnabled;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
 
 public class JNI_C implements CRFFI {
-    public static class JNI_CRFFINode extends CRFFINode {
+    public static class JNI_InvokeCNode extends InvokeCNode {
         /**
          * 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
@@ -39,8 +39,8 @@ public class JNI_C implements CRFFI {
          */
         @Override
         @TruffleBoundary
-        public void invoke(NativeCallInfo nativeCallInfo, Object[] args) {
-            synchronized (JNI_CRFFINode.class) {
+        public void execute(NativeCallInfo nativeCallInfo, Object[] args) {
+            synchronized (JNI_C.class) {
                 if (traceEnabled()) {
                     traceDownCall(nativeCallInfo.name, args);
                 }
@@ -52,7 +52,7 @@ public class JNI_C implements CRFFI {
     private static native void c(long address, Object[] args);
 
     @Override
-    public CRFFINode createCRFFINode() {
-        return new JNI_CRFFINode();
+    public InvokeCNode createInvokeCNode() {
+        return new JNI_InvokeCNode();
     }
 }
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 865f20619a28548366d37295b6cb5d7a48207324..f729327ebae99dc51f3e1a81c316acc35eb1d7ff 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
@@ -22,22 +22,17 @@
  */
 package com.oracle.truffle.r.runtime.ffi.jni;
 
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCall;
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCallReturn;
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceEnabled;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceDownCall;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceDownCallReturn;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceEnabled;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.nodes.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
-import com.oracle.truffle.r.runtime.ffi.DLL;
-import com.oracle.truffle.r.runtime.ffi.DLL.DLLException;
-import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
-import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
-import com.oracle.truffle.r.runtime.ffi.RFFIUtils;
 import com.oracle.truffle.r.runtime.ffi.RFFIVariables;
 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
@@ -46,17 +41,17 @@ import com.oracle.truffle.r.runtime.ffi.UpCallsRFFIFactory;
  * efficient).
  *
  * The JNI layer is not (currently) MT safe, so all calls are single threaded. N.B. Since the calls
- * take place from a {@link JNI_CallRFFINode}, and this is duplicated in separate contexts, we must
- * synchronize on the class.
+ * take place from nodes, and these may be duplicated in separate contexts, we must synchronize on
+ * the class.
  */
 public class JNI_Call implements CallRFFI {
 
-    public static class JNI_CallRFFINode extends CallRFFINode {
+    public static class JNI_InvokeCallNode extends InvokeCallNode {
 
         @Override
         @TruffleBoundary
-        public Object invokeCall(NativeCallInfo nativeCallInfo, Object[] args) {
-            synchronized (JNI_CallRFFINode.class) {
+        public Object execute(NativeCallInfo nativeCallInfo, Object[] args) {
+            synchronized (JNI_Call.class) {
                 long address = nativeCallInfo.address.asAddress();
                 Object result = null;
                 if (traceEnabled()) {
@@ -64,20 +59,20 @@ public class JNI_Call implements CallRFFI {
                 }
                 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
+                    // @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 {
@@ -87,11 +82,14 @@ public class JNI_Call implements CallRFFI {
                 }
             }
         }
+    }
+
+    public static class JNI_InvokeVoidCallNode extends InvokeVoidCallNode {
 
         @Override
         @TruffleBoundary
-        public void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args) {
-            synchronized (JNI_CallRFFINode.class) {
+        public void execute(NativeCallInfo nativeCallInfo, Object[] args) {
+            synchronized (JNI_Call.class) {
                 if (traceEnabled()) {
                     traceDownCall(nativeCallInfo.name, args);
                 }
@@ -115,68 +113,21 @@ public class JNI_Call implements CallRFFI {
             }
         }
 
-        @Override
-        public void setTempDir(String tempDir) {
-            synchronized (JNI_CallRFFINode.class) {
-                if (traceEnabled()) {
-                    traceDownCall("setTempDir", tempDir);
-                }
-                RFFIVariables.setTempDir(tempDir);
-                nativeSetTempDir(tempDir);
-                if (traceEnabled()) {
-                    traceDownCallReturn("setTempDir", null);
-                }
-            }
-        }
-
-        @Override
-        public void setInteractive(boolean interactive) {
-            synchronized (JNI_CallRFFINode.class) {
-                if (traceEnabled()) {
-                    traceDownCall("setInteractive", interactive);
-                }
-                nativeSetInteractive(interactive);
-                if (traceEnabled()) {
-                    traceDownCallReturn("setInteractive", null);
-                }
-            }
-        }
     }
 
-    private static final boolean ForceRTLDGlobal = false;
-
     public JNI_Call() {
-        loadLibRLibrary();
+        initialize();
     }
 
-    /**
-     * 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
-     * {@code RTLD_LOCAL} with {@code dlopen}, so we have to load the library manually and set
-     * {@code RTLD_GLOBAL}. However, a {@code dlopen} does not hook the JNI functions into the JVM,
-     * so we have to do an additional {@code System.load} to achieve that.
-     *
-     * Before we do that we must load {@code libjniboot} because the implementation of
-     * {@link DLLRFFI#dlopen} is called by {@link DLL#load} which uses JNI!
-     */
     @TruffleBoundary
-    private static void loadLibRLibrary() {
-        String libjnibootPath = LibPaths.getBuiltinLibPath("jniboot");
-        System.load(libjnibootPath);
+    private static void initialize() {
+        UpCallsRFFI upCallsRFFIImpl = RFFIUtils.initialize(new JNIUpCallsRFFIImpl());
 
-        String librffiPath = LibPaths.getBuiltinLibPath("R");
-        try {
-            DLL.loadLibR(librffiPath, ForceRTLDGlobal, false);
-        } catch (DLLException ex) {
-            throw new RInternalError(ex, "error while loading " + librffiPath);
-        }
-        System.load(librffiPath);
-        RFFIUtils.initialize();
         if (traceEnabled()) {
             traceDownCall("initialize");
         }
         try {
-            initialize(UpCallsRFFIFactory.getInstance().getUpcallsRFFI(), RFFIVariables.values());
+            initialize(upCallsRFFIImpl, RFFIVariables.initialize());
         } finally {
             if (traceEnabled()) {
                 traceDownCallReturn("initialize", null);
@@ -217,7 +168,12 @@ public class JNI_Call implements CallRFFI {
     private static native void callVoid1(long address, Object arg1);
 
     @Override
-    public CallRFFINode createCallRFFINode() {
-        return new JNI_CallRFFINode();
+    public InvokeCallNode createInvokeCallNode() {
+        return new JNI_InvokeCallNode();
+    }
+
+    @Override
+    public InvokeVoidCallNode createInvokeVoidCallNode() {
+        return new JNI_InvokeVoidCallNode();
     }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java
index 236b81e0048b1e566244f14fd659a86650e08669..697fe085b4f669cb57b35bf0076bd284dc74d25b 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_DLL.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,42 +23,38 @@
 package com.oracle.truffle.r.runtime.ffi.jni;
 
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 
 public class JNI_DLL implements DLLRFFI {
 
-    @Override
-    public Object dlopen(String path, boolean local, boolean now) {
-        long handle = native_dlopen(path, local, now);
-        if (handle == 0) {
-            return null;
-        } else {
+    public static class JNI_DLOpenNode extends DLOpenNode {
+        @Override
+        @TruffleBoundary
+        public Object execute(String path, boolean local, boolean now) throws UnsatisfiedLinkError {
+            long handle = native_dlopen(path, local, now);
             return new Long(handle);
         }
     }
 
-    @Override
-    public SymbolHandle dlsym(Object handle, String symbol) {
-        long nativeHandle = (Long) handle;
-        long symv = native_dlsym(nativeHandle, symbol);
-        if (symv == 0) {
-            // symbol might actually be zero
-            if (dlerror() != null) {
-                return null;
-            }
+    public static class JNI_DLSymNode extends DLSymNode {
+        @Override
+        @TruffleBoundary
+        public SymbolHandle execute(Object handle, String symbol) throws UnsatisfiedLinkError {
+            long nativeHandle = (Long) handle;
+            long symv = native_dlsym(nativeHandle, symbol);
+            return new SymbolHandle(symv);
         }
-        return new SymbolHandle(symv);
     }
 
-    @Override
-    public int dlclose(Object handle) {
-        long nativeHandle = (Long) handle;
-        return native_dlclose(nativeHandle);
-    }
+    public static class JNI_DLCloseNode extends DLCloseNode {
+        @Override
+        @TruffleBoundary
+        public int execute(Object handle) {
+            long nativeHandle = (Long) handle;
+            return native_dlclose(nativeHandle);
+        }
 
-    @Override
-    public String dlerror() {
-        return native_dlerror();
     }
 
     // Checkstyle: stop method name check
@@ -71,4 +67,19 @@ public class JNI_DLL implements DLLRFFI {
 
     private static native long native_dlsym(long handle, String symbol);
 
+    @Override
+    public DLOpenNode createDLOpenNode() {
+        return new JNI_DLOpenNode();
+    }
+
+    @Override
+    public DLSymNode createDLSymNode() {
+        return new JNI_DLSymNode();
+    }
+
+    @Override
+    public DLCloseNode createDLCloseNode() {
+        return new JNI_DLCloseNode();
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Misc.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Misc.java
index eb9acfc8566c51815bdb537e07d5a842ddb8bad8..25035bfc14be70f11f84b916ffb519ac8281e4eb 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Misc.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Misc.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,9 +22,9 @@
  */
 package com.oracle.truffle.r.runtime.ffi.jni;
 
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCall;
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceDownCallReturn;
-import static com.oracle.truffle.r.runtime.ffi.RFFIUtils.traceEnabled;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceDownCall;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceDownCallReturn;
+import static com.oracle.truffle.r.nodes.ffi.RFFIUtils.traceEnabled;
 
 import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 
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 f2bb99d0a828ee3419c5d69c137b4a70b08741e3..069de23ca3290fa8b497893d6d2083b9b72cc8cf 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,19 +28,23 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
 
 public class JNI_PCRE implements PCRERFFI {
-    private static class JNI_PCRERFFINode extends PCRERFFINode {
+    private static class JNI_MaketablesNode extends MaketablesNode {
         @Override
-        public long maketables() {
+        public long execute() {
             return nativeMaketables();
         }
+    }
 
+    private static class JNI_CompileNode extends CompileNode {
         @Override
-        public Result compile(String pattern, int options, long tables) {
+        public Result execute(String pattern, int options, long tables) {
             return nativeCompile(pattern, options, tables);
         }
+    }
 
+    private static class JNI_GetCaptureCountNode extends GetCaptureCountNode {
         @Override
-        public int getCaptureCount(long code, long extra) {
+        public int execute(long code, long extra) {
             int res = nativeGetCaptureCount(code, extra);
             if (res < 0) {
                 CompilerDirectives.transferToInterpreter();
@@ -48,9 +52,11 @@ public class JNI_PCRE implements PCRERFFI {
             }
             return res;
         }
+    }
 
+    private static class JNI_GetCaptureNamesNode extends GetCaptureNamesNode {
         @Override
-        public String[] getCaptureNames(long code, long extra, int captureCount) {
+        public String[] execute(long code, long extra, int captureCount) {
             String[] ret = new String[captureCount];
             int res = nativeGetCaptureNames(code, extra, ret);
             if (res < 0) {
@@ -59,14 +65,18 @@ public class JNI_PCRE implements PCRERFFI {
             }
             return ret;
         }
+    }
 
+    private static class JNI_StudyNode extends StudyNode {
         @Override
-        public Result study(long code, int options) {
+        public Result execute(long code, int options) {
             throw RInternalError.unimplemented("pcre_study");
         }
+    }
 
+    private static class JNI_ExecNode extends ExecNode {
         @Override
-        public int exec(long code, long extra, String subject, int offset, int options, int[] ovector) {
+        public int execute(long code, long extra, String subject, int offset, int options, int[] ovector) {
             return nativeExec(code, extra, subject, offset, options, ovector, ovector.length);
         }
     }
@@ -83,7 +93,33 @@ public class JNI_PCRE implements PCRERFFI {
                     int options, int[] ovector, int ovectorLen);
 
     @Override
-    public PCRERFFINode createPCRERFFINode() {
-        return new JNI_PCRERFFINode();
+    public MaketablesNode createMaketablesNode() {
+        return new JNI_MaketablesNode();
+    }
+
+    @Override
+    public CompileNode createCompileNode() {
+        return new JNI_CompileNode();
+    }
+
+    @Override
+    public GetCaptureCountNode createGetCaptureCountNode() {
+        return new JNI_GetCaptureCountNode();
     }
+
+    @Override
+    public GetCaptureNamesNode createGetCaptureNamesNode() {
+        return new JNI_GetCaptureNamesNode();
+    }
+
+    @Override
+    public StudyNode createStudyNode() {
+        return new JNI_StudyNode();
+    }
+
+    @Override
+    public ExecNode createExecNode() {
+        return new JNI_ExecNode();
+    }
+
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java
index 5729b0653039ee4191394d06ab64e5eefcc4ffaf..28f516f7c64c2464ff43763a4b5370b273d449f5 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_RFFIFactory.java
@@ -29,9 +29,11 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.CRFFI;
 import com.oracle.truffle.r.runtime.ffi.CallRFFI;
+import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.GridRFFI;
 import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
+import com.oracle.truffle.r.runtime.ffi.LibPaths;
 import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ffi.PCRERFFI;
 import com.oracle.truffle.r.runtime.ffi.RApplRFFI;
@@ -53,17 +55,30 @@ public class JNI_RFFIFactory extends RFFIFactory implements RFFI {
     public JNI_RFFIFactory() {
     }
 
-    @Override
-    protected void initialize(boolean runtime) {
-        // This must load early as package libraries reference symbols in it.
-        getCallRFFI();
-    }
-
-    /**
-     * Placeholder class for context-specific native state.
-     */
     private static class ContextStateImpl implements RContext.ContextState {
-
+        @Override
+        /**
+         * For the initial context, 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 {@code RTLD_LOCAL} with {@code dlopen}, so we have to
+         * load the library manually and set {@code RTLD_GLOBAL}. However, a {@code dlopen} does not
+         * hook the JNI functions into the JVM, so we have to do an additional {@code System.load}
+         * to achieve that.
+         *
+         * Before we do that we must load {@code libjniboot} because the implementation of
+         * {@link DLLRFFI.DLLRFFINode#dlopen} is called by {@link DLL#loadLibR} which uses JNI!
+         */
+        public ContextState initialize(RContext context) {
+            if (context.isInitial()) {
+                String libjnibootPath = LibPaths.getBuiltinLibPath("jniboot");
+                System.load(libjnibootPath);
+
+                String librffiPath = LibPaths.getBuiltinLibPath("R");
+                DLL.loadLibR(librffiPath);
+                System.load(librffiPath);
+            }
+            return this;
+        }
     }
 
     @Override
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 86040e7f39d36ce702448dced65b79c85b17e75c..49ab14598462af4ad3aa27a9b847d5e78a8cc2ab 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
@@ -23,52 +23,68 @@
 package com.oracle.truffle.r.runtime.ffi.jni;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
+import com.oracle.truffle.r.runtime.ffi.DLLRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ffi.StatsRFFI;
 
 public class JNI_Stats implements StatsRFFI {
 
-    public static class JNI_FFTNode extends FFTNode {
+    public static class JNI_WorkNode extends WorkNode {
+        private static final String FFT_WORK = "fft_work";
+        @Child DLLRFFI.DLSymNode dlSymNode = RFFIFactory.getRFFI().getDLLRFFI().createDLSymNode();
         private SymbolHandle fftWorkAddress;
-        private SymbolHandle fftFactorAddress;
 
         @Override
         @TruffleBoundary
-        public int executeWork(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
-            initialize();
+        public int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork) {
+            if (fftWorkAddress == null) {
+                fftWorkAddress = fftAddress(FFT_WORK, dlSymNode);
+            }
             return native_fft_work(fftWorkAddress.asAddress(), a, nseg, n, nspn, isn, work, iwork);
         }
+    }
+
+    public static class JNI_FactorNode extends FactorNode {
+        private static final String FFT_FACTOR = "fft_factor";
+        @Child DLLRFFI.DLSymNode dlSymNode = RFFIFactory.getRFFI().getDLLRFFI().createDLSymNode();
+        private SymbolHandle fftFactorAddress;
 
         @Override
         @TruffleBoundary
-        public void executeFactor(int n, int[] pmaxf, int[] pmaxp) {
-            initialize();
+        public void execute(int n, int[] pmaxf, int[] pmaxp) {
+            if (fftFactorAddress == null) {
+                fftFactorAddress = fftAddress(FFT_FACTOR, dlSymNode);
+            }
             native_fft_factor(fftFactorAddress.asAddress(), n, pmaxf, pmaxp);
 
         }
 
-        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");
-            fftAddress = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, symbol);
-            assert fftAddress != DLL.SYMBOL_NOT_FOUND;
-            return fftAddress;
+    private static SymbolHandle fftAddress(String symbol, DLLRFFI.DLSymNode dlSymNode) {
+        SymbolHandle fftAddress;
+        DLLInfo dllInfo = DLL.findLibrary("stats");
+        assert dllInfo != null;
+        try {
+            fftAddress = dlSymNode.execute(dllInfo.handle, symbol);
+        } catch (UnsatisfiedLinkError ex) {
+            throw RInternalError.shouldNotReachHere(ex);
         }
+        return fftAddress;
+    }
+
+    @Override
+    public FactorNode createFactorNode() {
+        return new JNI_FactorNode();
     }
 
     @Override
-    public FFTNode createFFTNode() {
-        return new JNI_FFTNode();
+    public WorkNode createWorkNode() {
+        return new JNI_WorkNode();
     }
 
     // Checkstyle: stop method name
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Zip.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Zip.java
index 452f10e67820918e49b697d238a416d5597a037d..7c93d004beeb22c062767dde7627518ee6c517b9 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Zip.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/JNI_Zip.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,18 +30,22 @@ import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
  */
 public class JNI_Zip implements ZipRFFI {
 
-    @Override
-    @TruffleBoundary
-    public int compress(byte[] dest, byte[] source) {
-        int rc = native_compress(dest, dest.length, source, source.length);
-        return rc;
+    public static class JNI_CompressNode extends ZipRFFI.CompressNode {
+        @Override
+        @TruffleBoundary
+        public int execute(byte[] dest, byte[] source) {
+            int rc = native_compress(dest, dest.length, source, source.length);
+            return rc;
+        }
     }
 
-    @Override
-    @TruffleBoundary
-    public int uncompress(byte[] dest, byte[] source) {
-        int rc = native_uncompress(dest, dest.length, source, source.length);
-        return rc;
+    public static class JNI_UncompressNode extends ZipRFFI.UncompressNode {
+        @Override
+        @TruffleBoundary
+        public int execute(byte[] dest, byte[] source) {
+            int rc = native_uncompress(dest, dest.length, source, source.length);
+            return rc;
+        }
     }
 
     // Checkstyle: stop method name
@@ -49,4 +53,14 @@ public class JNI_Zip implements ZipRFFI {
     private static native int native_compress(byte[] dest, long destlen, byte[] source, long sourcelen);
 
     private static native int native_uncompress(byte[] dest, long destlen, byte[] source, long sourcelen);
+
+    @Override
+    public CompressNode createCompressNode() {
+        return new JNI_CompressNode();
+    }
+
+    @Override
+    public UncompressNode createUncompressNode() {
+        return new JNI_UncompressNode();
+    }
 }
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
deleted file mode 100644
index 1b6d8aab816bc180e5a361d2e3311c02d40e3749..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jni/TraceUpCallsAdapter.java
+++ /dev/null
@@ -1,893 +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.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/RCompression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java
index 4cd19d58d717319b3708bed8aee98e1818ba806f..a1d9f81682824f9db676bb090289431879662522 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java
@@ -37,7 +37,7 @@ import java.util.zip.GZIPInputStream;
 
 import org.tukaani.xz.LZMA2InputStream;
 
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.ZipRFFI;
 
 /**
  * Abstracts the implementation of the various forms of compression used in R. Since the C API for
@@ -148,12 +148,12 @@ public class RCompression {
     }
 
     private static boolean gzipCompress(byte[] udata, byte[] cdata) {
-        int rc = RFFIFactory.getRFFI().getZipRFFI().compress(cdata, udata);
+        int rc = (int) ZipRFFI.CompressRootNode.create().getCallTarget().call(cdata, udata);
         return rc == 0;
     }
 
     private static boolean gzipUncompress(byte[] udata, byte[] data) {
-        int rc = RFFIFactory.getRFFI().getZipRFFI().uncompress(udata, data);
+        int rc = (int) ZipRFFI.UncompressRootNode.create().getCallTarget().call(udata, data);
         return rc == 0;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
index 426f5b569e5d7806695bf84bc7a7f996cb021f94..9c8ae0753becbf5e23ab8d663366ce364e93f35c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
@@ -904,50 +904,49 @@ public class RDeparse {
                 append("structure(");
                 return () -> {
                     DynamicObject attrs = ((RAttributable) obj).getAttributes();
-                    if (attrs != null) {
-                        Iterator<RAttributesLayout.RAttribute> iter = RAttributesLayout.asIterable(attrs).iterator();
-                        while (iter.hasNext()) {
-                            RAttributesLayout.RAttribute attr = iter.next();
-                            // TODO ignore function source attribute
-                            String attrName = attr.getName();
-                            append(", ");
-                            String dotName = null;
-                            switch (attrName) {
-                                case "dimnames":
-                                    dotName = ".Dimnames";
-                                    break;
-                                case "dim":
-                                    dotName = ".Dim";
-                                    break;
-                                case "names":
-                                    dotName = ".Names";
-                                    break;
-                                case "tsp":
-                                    dotName = ".Tsp";
-                                    break;
-                                case "levels":
-                                    dotName = ".Label";
-                                    break;
-
-                                default: {
-                                    opts = SIMPLEDEPARSE;
-                                    if (attrName.contains(" ")) {
-                                        append('"');
-                                        append(attrName);
-                                        append('"');
-                                    } else {
-                                        append(attrName);
-                                    }
+                    assert attrs != null;
+                    Iterator<RAttributesLayout.RAttribute> iter = RAttributesLayout.asIterable(attrs).iterator();
+                    while (iter.hasNext()) {
+                        RAttributesLayout.RAttribute attr = iter.next();
+                        // TODO ignore function source attribute
+                        String attrName = attr.getName();
+                        append(", ");
+                        String dotName = null;
+                        switch (attrName) {
+                            case "dimnames":
+                                dotName = ".Dimnames";
+                                break;
+                            case "dim":
+                                dotName = ".Dim";
+                                break;
+                            case "names":
+                                dotName = ".Names";
+                                break;
+                            case "tsp":
+                                dotName = ".Tsp";
+                                break;
+                            case "levels":
+                                dotName = ".Label";
+                                break;
+
+                            default: {
+                                opts = SIMPLEDEPARSE;
+                                if (attrName.contains(" ")) {
+                                    append('"');
+                                    append(attrName);
+                                    append('"');
+                                } else {
+                                    append(attrName);
                                 }
                             }
-                            if (dotName != null) {
-                                append(dotName);
-                            }
-                            append(" = ");
-                            appendValue(attr.getValue());
-                            append(')');
                         }
+                        if (dotName != null) {
+                            append(dotName);
+                        }
+                        append(" = ");
+                        appendValue(attr.getValue());
                     }
+                    append(')');
                 };
             } else {
                 return () -> {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
index b981424ae510db9e3aca3b7dabacd3ab249fc86f..86e5fd3060d651cf32dabc5af790f02b2f28b6bd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@ import java.util.Map;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 /**
  * Repository for environment variables, including those set by FastR itself, e.g.
@@ -88,7 +88,7 @@ public final class REnvVars implements RContext.ContextState {
             String userFile = envVars.get("R_ENVIRON_USER");
             if (userFile == null) {
                 String dotRenviron = ".Renviron";
-                userFile = fileSystem.getPath(RFFIFactory.getRFFI().getBaseRFFI().getwd(), dotRenviron).toString();
+                userFile = fileSystem.getPath((String) BaseRFFI.GetwdRootNode.create().getCallTarget().call(), dotRenviron).toString();
                 if (!new File(userFile).exists()) {
                     userFile = fileSystem.getPath(System.getProperty("user.home"), dotRenviron).toString();
                 }
@@ -160,9 +160,9 @@ public final class REnvVars implements RContext.ContextState {
 
     /**
      * Returns the value of the {@code R_HOME} environment variable (setting it in the unusual case
-     * where it it is not set by the initiating shell scripts. This is called very early in the
-     * startup as it is required to access the native libraries, before the initial context is
-     * initialized and, therefore, before {@link #envVars} is available.
+     * where it it is not set by the initiating shell scripts. This may be called very early in the
+     * startup possibly before the initial context is initialized and, therefore, before
+     * {@link #envVars} is available.
      */
     public static String rHome() {
         if (rHome == null) {
@@ -216,8 +216,11 @@ public final class REnvVars implements RContext.ContextState {
     private void checkRHome() {
         String envRHome = envVars.get(R_HOME);
         if (envRHome == null) {
-            assert rHome != null;
-            envVars.put(R_HOME, rHome);
+            envVars.put(R_HOME, rHome());
+        } else {
+            if (rHome == null) {
+                rHome = envRHome;
+            }
         }
     }
 
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 f0a8433fdbc67f01c81da9b60ed8dcf87b58853a..da3597e88002595c1b56624f8bdbc740d118adca 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
@@ -236,6 +236,7 @@ public final class RError extends RuntimeException {
          */
         GENERIC("%s"),
         TOO_SHORT("'%s' is too short"),
+        INVALID_DATA_OF_TYPE_TOO_SHORT("invalid data of mode '%s' (too short)"),
         VECTOR_SIZE_TOO_LARGE("vector size specified is too large"),
         ARG_RECYCYLED("an argument will be fractionally recycled"),
         LENGTH_GT_1("the condition has length > 1 and only the first element will be used"),
@@ -409,6 +410,7 @@ public final class RError extends RuntimeException {
         PROMISE_CYCLE("promise already under evaluation: recursive default argument reference or earlier problems?"),
         MISSING_ARGUMENTS("'missing' can only be used for arguments"),
         INVALID_ENVIRONMENT("invalid environment"),
+        INVALID_ENVIRONMENT_SPECIFIED("invalid environment specified"),
         ENVIR_NOT_LENGTH_ONE("numeric 'envir' arg not of length one"),
         FMT_NOT_CHARACTER("'fmt' is not a character vector"),
         UNSUPPORTED_TYPE("unsupported type"),
@@ -453,6 +455,7 @@ public final class RError extends RuntimeException {
         INVALID_SUBSCRIPT_TYPE("invalid subscript type '%s'"),
         ARGUMENT_NOT_VECTOR("argument %d is not a vector"),
         CANNOT_COERCE("cannot coerce type '%s' to vector of type '%s'"),
+        CANNOT_COERCE_RFFI("(%s) object cannot be coerced to type '%s'"),
         ARGUMENT_ONLY_FIRST("argument '%s' has length > 1 and only the first element will be used"),
         ARGUMENT_ONLY_FIRST_1("only the first element of '%s' argument used"),
         ARGUMENT_WRONG_LENGTH("wrong length for argument"),
@@ -559,6 +562,7 @@ public final class RError extends RuntimeException {
         INVALID_LOGICAL("'%s' must be TRUE or FALSE"),
         INVALID_FORMAT_STRING("invalid format '%s'; use format %%s for character objects"),
         MUST_BE_CHARACTER("'%s' must be of mode character"),
+        FIRST_ARGUMENT_MUST_BE_CHARACTER("the first argument must be of mode character"),
         ALL_ATTRIBUTES_NAMES("all attributes must have names [%d does not]"),
         INVALID_REGEXP("invalid regular expression '%s'"),
         COERCING_ARGUMENT("coercing argument of type '%s' to %s"),
@@ -598,6 +602,7 @@ public final class RError extends RuntimeException {
         NOT_A_SYMBOL("not a symbol"),
         CANNOT_SET_PARENT("cannot set the parent of the empty environment"),
         INVALID_OR_UNIMPLEMENTED_ARGUMENTS("invalid or unimplemented arguments"),
+        INVALID_LIST_FOR_SUBSTITUTION("invalid list for substitution"),
         NOTHING_TO_LINK("nothing to link"),
         FROM_TO_DIFFERENT("'from' and 'to' are of different lengths"),
         NA_IN_FOREIGN_FUNCTION_CALL("NAs in foreign function call (arg %d)"),
@@ -738,7 +743,6 @@ public final class RError extends RuntimeException {
         QUIT_INVALID_STATUS("invalid 'status', 0 assumed"),
         QUIT_INVALID_RUNLAST("invalid 'runLast', FALSE assumed"),
         ENVIRONMENTS_COERCE("environments cannot be coerced to other types"),
-        CLOSURE_COERCE("cannot coerce type 'closure' to vector of type 'integer'"),
         ROWSUM_NAMES_NOT_CHAR("row names are not character"),
         ROWSUM_NON_NUMERIC("non-numeric matrix in rowsum(): this should not happen"),
         ARGUMENTS_REQUIRED_COUNT("%d arguments to '%s' which requires %d"),
@@ -748,7 +752,7 @@ public final class RError extends RuntimeException {
         SYSTEM_CHAR_ARG("non-empty character argument expected"),
         SYSTEM_INTERN_NOT_NA("'intern' must be logical and not NA"),
         NO_SUCH_FILE("cannot open file '%s': No such file or directory"),
-        NON_STRING_ARG_TO_INTERNAL_PASTE("non-string argument to Internal paste"),
+        NON_STRING_ARG_TO_INTERNAL_PASTE("non-string argument to internal 'paste'"),
         INVALID_STRING_IN_STOP(" [invalid string in stop(.)]"),
         INVALID_STRING_IN_WARNING(" [invalid string in warning(.)]"),
         ERR_MSG_MUST_BE_STRING("error message must be a character string"),
@@ -777,11 +781,13 @@ public final class RError extends RuntimeException {
         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'"),
-        TOO_MANY_ARGS("too many arguments"),
         ARG_MUST_BE_CHARACTER("argument '%s' must be character"),
         INCORRECT_NOF_ARGS("Incorrect number of arguments (%d), expecting %d for '%s'"),
         MACRO_CAN_BE_APPLIED_TO("%s can only be applied to a '%s', not a '%s'"),
-        LOSS_OF_ACCURACY_MOD("probable complete loss of accuracy in modulus");
+        LOSS_OF_ACCURACY_MOD("probable complete loss of accuracy in modulus"),
+        LENGTH_MISAPPLIED("LENGTH or similar applied to %s object"),
+        TOO_MANY_ARGS("too many arguments"),
+        UNIMPLEMENTED_TYPE_IN_R("type \"%s\" unimplemented in R");
 
         public final String message;
         final boolean hasArgs;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
index 3af2daa50e1ea8b7403d0e223a2bc9e9ddf3bfbf..acd5193d5732cb56b231ee7a303c9bd8e5df8726 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@ import java.nio.file.Path;
 
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 /**
  * Handles the setup of system, site and user profile code. N.B. this class only reads the files and
@@ -68,7 +68,7 @@ public final class RProfile implements RContext.ContextState {
             String userProfilePath = envVars.get("R_PROFILE_USER");
             if (userProfilePath == null) {
                 String dotRenviron = ".Rprofile";
-                userProfilePath = fileSystem.getPath(RFFIFactory.getRFFI().getBaseRFFI().getwd(), dotRenviron).toString();
+                userProfilePath = fileSystem.getPath((String) BaseRFFI.GetwdRootNode.create().getCallTarget().call(), dotRenviron).toString();
                 if (!new File(userProfilePath).exists()) {
                     userProfilePath = fileSystem.getPath(System.getProperty("user.home"), dotRenviron).toString();
                 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
index 0888d7ceece1733710fe1b438e4d3c4b7ae67d0d..31938c37b52c0ee0b9047c16445fbaa20d0d594d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
@@ -28,16 +28,8 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 /**
  * A facade for the creation of Truffle {@link Source} objects, which is complicated in R due the
@@ -209,45 +201,4 @@ public class RSource {
         }
     }
 
-    @TruffleBoundary
-    public static Object createSrcRef(SourceSection src) {
-        if (src == null) {
-            return RNull.instance;
-        }
-        if (src == RSyntaxNode.INTERNAL || src == RSyntaxNode.LAZY_DEPARSE || src == RSyntaxNode.SOURCE_UNAVAILABLE) {
-            return RNull.instance;
-        }
-        Source source = src.getSource();
-        REnvironment env = RContext.getInstance().sourceRefEnvironments.get(source);
-        if (env == null) {
-            env = RDataFactory.createNewEnv("src");
-            env.setClassAttr(RDataFactory.createStringVector(new String[]{"srcfilecopy", "srcfile"}, true));
-            try {
-                env.put("filename", source.getPath() == null ? "" : source.getPath());
-                env.put("fixedNewlines", RRuntime.LOGICAL_TRUE);
-                String[] lines = new String[source.getLineCount()];
-                for (int i = 0; i < lines.length; i++) {
-                    lines[i] = source.getCode(i + 1);
-                }
-                env.put("lines", RDataFactory.createStringVector(lines, true));
-            } catch (PutException e) {
-                throw RInternalError.shouldNotReachHere(e);
-            }
-            RContext.getInstance().sourceRefEnvironments.put(source, env);
-        }
-        /*
-         * TODO: it's unclear what the exact format is, experimentally it is (first line, first
-         * column, last line, last column, first column, last column, first line, last line). the
-         * second pair of columns is likely bytes instead of chars, and the second pair of lines
-         * parsed as opposed to "real" lines (may be modified by #line).
-         */
-        int startLine = src.getStartLine();
-        int startColumn = src.getStartColumn();
-        int endLine = src.getEndLine();
-        int endColumn = src.getEndColumn();
-        RIntVector ref = RDataFactory.createIntVector(new int[]{startLine, startColumn, endLine, endColumn, startColumn, endColumn, startLine, endLine}, true);
-        ref.setAttr("srcfile", env);
-        ref.setClassAttr(RDataFactory.createStringVector("srcref"));
-        return ref;
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSrcref.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSrcref.java
index 911ee913029030ab83a7e411cc94f16c8567a998..d2a27b63774482b121dc835c85c905c982377e17 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSrcref.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSrcref.java
@@ -20,11 +20,15 @@ import java.nio.file.attribute.PosixFileAttributes;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 /**
  * Utilities for handling R srcref attributes, in particular conversion from {@link Source},
@@ -75,7 +79,7 @@ public class RSrcref {
         env.safePut(SrcrefFields.timestamp.name(), mtime);
         env.safePut(SrcrefFields.filename.name(), path.toString());
         env.safePut(SrcrefFields.isFile.name(), RRuntime.LOGICAL_TRUE);
-        env.safePut(SrcrefFields.wd.name(), RFFIFactory.getRFFI().getBaseRFFI().getwd());
+        env.safePut(SrcrefFields.wd.name(), BaseRFFI.GetwdRootNode.create().getCallTarget().call());
         env.setClassAttr(SRCFILE_ATTR);
         return env;
     }
@@ -89,8 +93,43 @@ public class RSrcref {
         return createLloc(ss, createSrcfile(path));
     }
 
+    @TruffleBoundary
+    public static Object createLloc(SourceSection src) {
+        if (src == null) {
+            return RNull.instance;
+        }
+        if (src == RSyntaxNode.INTERNAL || src == RSyntaxNode.LAZY_DEPARSE || src == RSyntaxNode.SOURCE_UNAVAILABLE) {
+            return RNull.instance;
+        }
+        Source source = src.getSource();
+        REnvironment env = RContext.getInstance().sourceRefEnvironments.get(source);
+        if (env == null) {
+            env = RDataFactory.createNewEnv("src");
+            env.setClassAttr(RDataFactory.createStringVector(new String[]{"srcfilecopy", RRuntime.R_SRCFILE}, true));
+            try {
+                env.put("filename", source.getPath() == null ? "" : source.getPath());
+                env.put("fixedNewlines", RRuntime.LOGICAL_TRUE);
+                String[] lines = new String[source.getLineCount()];
+                for (int i = 0; i < lines.length; i++) {
+                    lines[i] = source.getCode(i + 1);
+                }
+                env.put("lines", RDataFactory.createStringVector(lines, true));
+            } catch (PutException e) {
+                throw RInternalError.shouldNotReachHere(e);
+            }
+            RContext.getInstance().sourceRefEnvironments.put(source, env);
+        }
+        return createLloc(src, env);
+    }
+
     @TruffleBoundary
     public static RIntVector createLloc(SourceSection ss, REnvironment srcfile) {
+        /*
+         * TODO: it's unclear what the exact format is, experimentally it is (first line, first
+         * column, last line, last column, first column, last column, first line, last line). the
+         * second pair of columns is likely bytes instead of chars, and the second pair of lines
+         * parsed as opposed to "real" lines (may be modified by #line).
+         */
         int[] llocData = new int[8];
         int startLine = ss.getStartLine();
         int startColumn = ss.getStartColumn();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionInfo.java
index 4d277298b2dd4dd55e699bbc27c5d82b9ff595df..6336fb8835fb96f7a1b51dd13271d8cf0c45778f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionInfo.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RVersionInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,9 +22,10 @@
  */
 package com.oracle.truffle.r.runtime;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI.UtsName;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
 public enum RVersionInfo {
     // @formatter:off
@@ -45,8 +46,8 @@ public enum RVersionInfo {
     public static final int SERIALIZE_VERSION = (2 << 16) + (3 << 8) + 0;
 
     @CompilationFinal private static final RVersionInfo[] VALUES = RVersionInfo.values();
-    @CompilationFinal private static final String[] LIST_VALUES = new String[VALUES.length];
-    @CompilationFinal private static final String[] LIST_NAMES = new String[VALUES.length];
+    @CompilationFinal private static String[] ListValues;
+    @CompilationFinal private static String[] ListNames;
 
     private final String listName;
     private String value;
@@ -76,49 +77,56 @@ public enum RVersionInfo {
         return Character.toLowerCase(s.charAt(0)) + s.substring(1);
     }
 
-    public static void initialize() {
-        UtsName utsname = RFFIFactory.getRFFI().getBaseRFFI().uname();
-        String osName = toFirstLower(utsname.sysname());
-        String vendor = osName.equals("darwin") ? "apple" : "unknown";
-        OS.value = osName + utsname.release();
-        for (int i = 0; i < VALUES.length; i++) {
-            RVersionInfo data = VALUES[i];
-            LIST_NAMES[i] = data.listName;
-            if (data.value == null) {
-                switch (data) {
-                    case Platform:
-                        /*
-                         * FIXME In order to match the info in the default packages copied from
-                         * GnuR, this value on Linux has to be x86_64-unknown-linux-gnu
-                         */
-                        if (osName.equals("linux")) {
-                            if (Arch.value.equals("sparcv9")) {
-                                data.value = "sparc64-unknown-linux-gnu";
+    private static void initialize() {
+        if (ListValues == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            ListValues = new String[VALUES.length];
+            ListNames = new String[VALUES.length];
+            UtsName utsname = (UtsName) BaseRFFI.UnameRootNode.create().getCallTarget().call();
+            String osName = toFirstLower(utsname.sysname());
+            String vendor = osName.equals("darwin") ? "apple" : "unknown";
+            OS.value = osName + utsname.release();
+            for (int i = 0; i < VALUES.length; i++) {
+                RVersionInfo data = VALUES[i];
+                ListNames[i] = data.listName;
+                if (data.value == null) {
+                    switch (data) {
+                        case Platform:
+                            /*
+                             * FIXME In order to match the info in the default packages copied from
+                             * GnuR, this value on Linux has to be x86_64-unknown-linux-gnu
+                             */
+                            if (osName.equals("linux")) {
+                                if (Arch.value.equals("sparcv9")) {
+                                    data.value = "sparc64-unknown-linux-gnu";
+                                } else {
+                                    data.value = "x86_64-unknown-linux-gnu";
+                                }
+                            } else if (osName.toLowerCase().equals("sunos")) {
+                                data.value = "sparc-sun-solaris2.11";
                             } else {
-                                data.value = "x86_64-unknown-linux-gnu";
+                                data.value = Arch.value + "-" + vendor + "-" + OS.value;
                             }
-                        } else if (osName.toLowerCase().equals("sunos")) {
-                            data.value = "sparc-sun-solaris2.11";
-                        } else {
-                            data.value = Arch.value + "-" + vendor + "-" + OS.value;
-                        }
-                        break;
-                    case System:
-                        data.value = Arch.value + ", " + OS.value;
-                        break;
-                    default:
-                        data.value = "";
+                            break;
+                        case System:
+                            data.value = Arch.value + ", " + OS.value;
+                            break;
+                        default:
+                            data.value = "";
+                    }
                 }
+                ListValues[i] = data.value;
             }
-            LIST_VALUES[i] = data.value;
         }
     }
 
     public static String[] listNames() {
-        return LIST_NAMES;
+        initialize();
+        return ListNames;
     }
 
     public static String[] listValues() {
-        return LIST_VALUES;
+        initialize();
+        return ListValues;
     }
 }
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 fcc8f9710fb7126add02d5490531426fe29d5974..d0783f13cffee5b279ee86f5b0d07b9da968cd97 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,48 +28,48 @@ import java.nio.file.Path;
 import java.util.Random;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 /**
  *
- * As per the GnuR spec, the tempdir() directory is identified on startup.
+ * As per the GnuR spec, the tempdir() directory is identified on startup. It <b>must</b>be
+ * initialized before the first RFFI call as the value is available in the R FFI.
  *
  */
-public class TempPathName {
+public class TempPathName implements RContext.ContextState {
     private static final String RANDOM_CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyz";
     private static final int RANDOM_CHARACTERS_LENGTH = RANDOM_CHARACTERS.length();
     private static final int RANDOM_LENGTH = 12; // as per GnuR
-
-    private static String tempDirPath;
     private static final Random rand = new Random();
 
-    public static void initialize() {
-        if (tempDirPath == null) {
-            //
-            final String[] envVars = new String[]{"TMPDIR", "TMP", "TEMP"};
-            String startingTempDir = null;
-            for (String envVar : envVars) {
-                String value = System.getenv(envVar);
-                if (value != null && isWriteableDirectory(value)) {
-                    startingTempDir = value;
-                }
-            }
-            if (startingTempDir == null) {
-                startingTempDir = "/tmp";
-            }
-            Path startingTempDirPath = FileSystems.getDefault().getPath(startingTempDir, "Rtmp");
-            // ensure absolute, to avoid problems with R code does a setwd
-            if (!startingTempDirPath.isAbsolute()) {
-                startingTempDirPath = startingTempDirPath.toAbsolutePath();
-            }
-            String t = RFFIFactory.getRFFI().getBaseRFFI().mkdtemp(startingTempDirPath.toString() + "XXXXXX");
-            if (t != null) {
-                tempDirPath = t;
-            } else {
-                Utils.rSuicide("cannot create 'R_TempDir'");
+    private String tempDirPath;
+
+    @Override
+    public RContext.ContextState initialize(RContext context) {
+        final String[] envVars = new String[]{"TMPDIR", "TMP", "TEMP"};
+        String startingTempDir = null;
+        for (String envVar : envVars) {
+            String value = System.getenv(envVar);
+            if (value != null && isWriteableDirectory(value)) {
+                startingTempDir = value;
             }
-            RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode().setTempDir(tempDirPath);
         }
+        if (startingTempDir == null) {
+            startingTempDir = "/tmp";
+        }
+        Path startingTempDirPath = FileSystems.getDefault().getPath(startingTempDir, "Rtmp");
+        // ensure absolute, to avoid problems with R code does a setwd
+        if (!startingTempDirPath.isAbsolute()) {
+            startingTempDirPath = startingTempDirPath.toAbsolutePath();
+        }
+        String t = (String) BaseRFFI.MkdtempRootNode.create().getCallTarget().call(startingTempDirPath.toString() + "XXXXXX");
+        if (t != null) {
+            tempDirPath = t;
+        } else {
+            Utils.rSuicide("cannot create 'R_TempDir'");
+        }
+        return this;
     }
 
     private static boolean isWriteableDirectory(String path) {
@@ -78,7 +78,11 @@ public class TempPathName {
     }
 
     public static String tempDirPath() {
-        return tempDirPath;
+        return RContext.getInstance().stateTempPath.tempDirPath;
+    }
+
+    public static TempPathName newContextState() {
+        return new TempPathName();
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
index 5675ee5be14d8de44030d5cefe85b09feb29df21..19bb59be1350811d3a3a9589b789120af257b0a2 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
@@ -60,6 +60,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
@@ -284,7 +285,7 @@ public final class Utils {
      */
     public static Path getLogPath(String fileName) {
         String root = RContext.isEmbedded() ? "/tmp" : REnvVars.rHome();
-        int pid = RFFIFactory.getRFFI().getBaseRFFI().getpid();
+        int pid = (int) BaseRFFI.GetpidRootNode.create().getCallTarget().call();
         String baseName = RContext.isEmbedded() ? fileName + "-" + Integer.toString(pid) : fileName;
         return FileSystems.getDefault().getPath(root, baseName);
     }
@@ -368,7 +369,7 @@ public final class Utils {
             @Override
             public Frame visitFrame(FrameInstance frameInstance) {
                 if (!first) {
-                    Frame pf = frameInstance.getFrame(fa, false);
+                    Frame pf = frameInstance.getFrame(fa);
                     Frame f = RArguments.unwrap(pf);
                     if (RArguments.isRFrame(f)) {
                         return RArguments.getCall(f) == target ? f : null;
@@ -393,7 +394,7 @@ public final class Utils {
             @Override
             public Frame visitFrame(FrameInstance frameInstance) {
                 if (!first) {
-                    Frame pf = frameInstance.getFrame(fa, false);
+                    Frame pf = frameInstance.getFrame(fa);
                     Frame f = RArguments.unwrap(pf);
                     if (RArguments.isRFrame(f)) {
                         RCaller call = RArguments.getCall(f);
@@ -423,7 +424,7 @@ public final class Utils {
             @Override
             public T visitFrame(FrameInstance frameInstance) {
                 if (!first) {
-                    Frame f = RArguments.unwrap(frameInstance.getFrame(fa, false));
+                    Frame f = RArguments.unwrap(frameInstance.getFrame(fa));
                     if (RArguments.isRFrame(f)) {
                         return func.apply(f);
                     } else {
@@ -468,7 +469,7 @@ public final class Utils {
             // Truffle/R system has started
             return null;
         }
-        return RArguments.unwrap(frameInstance.getFrame(FrameAccess.MATERIALIZE, true));
+        return RArguments.unwrap(frameInstance.getFrame(FrameAccess.MATERIALIZE));
     }
 
     private static final class TracebackVisitor implements FrameInstanceVisitor<Frame> {
@@ -483,7 +484,7 @@ public final class Utils {
         @Override
         @TruffleBoundary
         public Frame visitFrame(FrameInstance frameInstance) {
-            Frame f = RArguments.unwrap(frameInstance.getFrame(FrameAccess.READ_ONLY, true));
+            Frame f = RArguments.unwrap(frameInstance.getFrame(FrameAccess.READ_ONLY));
             if (!RArguments.isRFrame(f) || RArguments.getFunction(f) == null) {
                 return null;
             }
@@ -548,13 +549,13 @@ public final class Utils {
         } else {
             StringBuilder str = new StringBuilder();
             Truffle.getRuntime().iterateFrames(frameInstance -> {
-                dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true), false, frameInstance.isVirtualFrame());
+                dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY), false, frameInstance.isVirtualFrame());
                 return null;
             });
             if (printFrameSlots) {
                 str.append("\n\nwith frame slot contents:\n");
                 Truffle.getRuntime().iterateFrames(frameInstance -> {
-                    dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true), true, frameInstance.isVirtualFrame());
+                    dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY), true, frameInstance.isVirtualFrame());
                     return null;
                 });
             }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java
index 10e9a7ce172cdb19cf95775c1b76f9566cca8bc4..77c0e2875edf4e45f279d1eea5742f279efdd91d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java
@@ -462,8 +462,7 @@ public class FileConnections {
             raf.seek(writeOffset);
             byte[] sepData = sep.getBytes();
             for (int i = 0; i < lines.getLength(); i++) {
-                byte[] data = lines.getDataAt(i).getBytes();
-                raf.write(data);
+                writeString(lines.getDataAt(i), false);
                 raf.write(sepData);
             }
             writeOffset = raf.getFilePointer();
@@ -476,7 +475,10 @@ public class FileConnections {
 
         @Override
         public void writeString(String s, boolean nl) throws IOException {
-            throw RInternalError.unimplemented();
+            raf.write(s.getBytes());
+            if (nl) {
+                raf.writeBytes(System.lineSeparator());
+            }
         }
 
         @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
index 781156ff27b2b2ae3d7d66fc72940b0d0c19f42a..5e7770a8eaeb9140f95c3644caaea817a0a685f7 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 import com.oracle.truffle.api.interop.ForeignAccess;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.vm.PolyglotEngine;
+import com.oracle.truffle.r.runtime.RCmdOptions;
+import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 
@@ -98,8 +100,23 @@ public final class ContextInfo implements TruffleObject {
         return create(startParams, env, kind, parent, consoleHandler, TimeZone.getDefault());
     }
 
+    /**
+     * Create a context configuration object such that FastR does not restore previously stored
+     * sessions on startup.
+     *
+     * @param env TODO
+     * @param kind defines the degree to which this context shares base and package environments
+     *            with its parent
+     * @param parent if non-null {@code null}, the parent creating the context
+     * @param consoleHandler a {@link ConsoleHandler} for output
+     */
+    public static ContextInfo createNoRestore(Client client, String[] env, ContextKind kind, RContext parent, ConsoleHandler consoleHandler) {
+        RStartParams params = new RStartParams(RCmdOptions.parseArguments(client, new String[]{"--no-restore"}, false), false);
+        return create(params, env, kind, parent, consoleHandler);
+    }
+
     public static ContextInfo getContextInfo(PolyglotEngine vm) {
-        return (ContextInfo) vm.findGlobalSymbol(ContextInfo.GLOBAL_SYMBOL).get();
+        return vm.findGlobalSymbol(ContextInfo.GLOBAL_SYMBOL).as(ContextInfo.class);
     }
 
     public RStartParams getStartParams() {
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 aad5eb33e01e773b1cb159a29ad1e9bb514f7cb8..d9f04b454e74e5a5d15e8939021f8cd8316932ce 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
@@ -63,6 +63,7 @@ import com.oracle.truffle.r.runtime.RRuntimeASTAccess;
 import com.oracle.truffle.r.runtime.RSerialize;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RStartParams;
+import com.oracle.truffle.r.runtime.TempPathName;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
@@ -76,7 +77,6 @@ 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;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
@@ -438,6 +438,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
      * processor, but the set is relatively small, so we just enumerate them here.
      */
     public final REnvVars stateREnvVars;
+    public final TempPathName stateTempPath;
     public final RProfile stateRProfile;
     public final StdConnections.ContextStateImpl stateStdConnections;
     public final ROptions.ContextStateImpl stateROptions;
@@ -484,16 +485,19 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         if (initialInfo == null) {
             /*
              * This implies that FastR is being invoked initially from another Truffle language and
-             * not via RCommand/RscriptCommand.
+             * not via RCommand/RscriptCommand. In this case, we also assume that no previously
+             * stored session should be restored.
              */
-            this.info = ContextInfo.create(new RStartParams(RCmdOptions.parseArguments(Client.R, new String[0], false), false), null,
+            this.info = ContextInfo.create(new RStartParams(RCmdOptions.parseArguments(Client.R, new String[]{"--no-restore"}, false), false), null,
                             ContextKind.SHARE_NOTHING, null, new DefaultConsoleHandler(env.in(), env.out()));
         } else {
             this.info = initialInfo;
         }
+
         this.initial = isInitial;
         this.env = env;
         this.stateREnvVars = REnvVars.newContextState();
+        this.stateTempPath = TempPathName.newContextState();
         this.stateROptions = ROptions.ContextStateImpl.newContextState(stateREnvVars);
         this.stateRProfile = RProfile.newContextState(stateREnvVars);
         this.stateStdConnections = StdConnections.ContextStateImpl.newContextState();
@@ -554,6 +558,11 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         attachThread();
         state.add(State.ATTACHED);
 
+        stateDLL.initialize(this);
+        stateRFFI = RFFIFactory.getInstance().newContextState();
+        // separate in case initialize calls getStateRFFI()!
+        stateRFFI.initialize(this);
+
         if (!embedded) {
             doEnvOptionsProfileInitialization();
         }
@@ -563,14 +572,10 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         stateRConnection.initialize(this);
         stateStdConnections.initialize(this);
         stateRNG.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) {
@@ -589,7 +594,6 @@ public final class RContext extends ExecutionContext implements TruffleObject {
             this.methodTableDispatchOn = info.getParent().methodTableDispatchOn;
         }
         if (initial && !embedded) {
-            RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode().setInteractive(isInteractive());
             initialContextInitialized = true;
         }
         return this;
@@ -601,6 +605,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
      */
     private void doEnvOptionsProfileInitialization() {
         stateREnvVars.initialize(this);
+        stateTempPath.initialize(this);
         stateROptions.initialize(this);
         stateRProfile.initialize(this);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypesFlatLayout.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypesFlatLayout.java
index ed769f7b79bb5da49e260d32d43b057406d81318..b0c6f4bbb0b8657cf152bd2be46dd695523c0903 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypesFlatLayout.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypesFlatLayout.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@ import com.oracle.truffle.api.dsl.TypeCheck;
 import com.oracle.truffle.api.dsl.TypeSystem;
 import com.oracle.truffle.api.dsl.internal.DSLOptions;
 import com.oracle.truffle.api.dsl.internal.DSLOptions.DSLGenerator;
+import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -300,4 +301,77 @@ public class RTypesFlatLayout {
     public static RMissing toRMissing(@SuppressWarnings("unused") REmpty empty) {
         return RMissing.instance;
     }
+
+    // RAbstractAtomicVector
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(int value) {
+        return RDataFactory.createIntVectorFromScalar(value);
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(double value) {
+        return RDataFactory.createDoubleVectorFromScalar(value);
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RRaw value) {
+        return RDataFactory.createRawVectorFromScalar(value);
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(byte value) {
+        return RDataFactory.createLogicalVectorFromScalar(value);
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RComplex value) {
+        return RDataFactory.createComplexVectorFromScalar(value);
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(String value) {
+        return RDataFactory.createStringVectorFromScalar(value);
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RIntVector vector) {
+        return vector;
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RDoubleVector vector) {
+        return vector;
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RLogicalVector vector) {
+        return vector;
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RComplexVector vector) {
+        return vector;
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RRawVector vector) {
+        return vector;
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RStringVector vector) {
+        return vector;
+    }
+
+    @ImplicitCast
+    public static RAbstractAtomicVector toAbstractAtomicVector(RIntSequence vector) {
+        return vector;
+    }
+
+    @ImplicitCast
+    public static RAbstractVector toAbstractAtomicVector(RDoubleSequence vector) {
+        return vector;
+    }
+
 }
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 e40efafa8eb52cfaef95ee52765ad52b2f30401d..e5e7d62026859376ee80d452416cc5d7a00c15be 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
+import static com.oracle.truffle.r.runtime.RError.NO_CALLER;
+
 import java.util.function.Function;
 
 import com.oracle.truffle.api.CompilerAsserts;
@@ -472,7 +474,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     @Override
     public final void setDimensions(int[] newDimensions) {
-        setDimensions(newDimensions, null);
+        setDimensions(newDimensions, NO_CALLER);
     }
 
     private void setDimensions(int[] newDimensions, RBaseNode invokingNode) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractAtomicVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractAtomicVector.java
new file mode 100644
index 0000000000000000000000000000000000000000..839804eb00977d5f6b0de425e5a232f2b5e428cc
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractAtomicVector.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.data.model;
+
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
+
+/**
+ * Distinguishes what R considers an "atomic" vector, e.g. {@code integer()} from other "vectors",
+ * e.g., {@code list()}. Specifically these are the FastR atomic vector types:
+ * <ul>
+ * <li>{@link RAbstractIntVector}</li>
+ * <li>{@link RAbstractLogicalVector}</li>
+ * <li>{@link RAbstractDoubleVector}</li>
+ * <li>{@link RAbstractComplexVector}</li>
+ * <li>{@link RAbstractStringVector}</li>
+ * <li>{@link RAbstractRawVector}</li>
+ * </ul>
+ *
+ * N.B. To use this in a {@link Specialization} you must use {@link RTypesFlatLayout}.
+ */
+public interface RAbstractAtomicVector extends RAbstractVector {
+
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
index e3a04b41338a8e0160adcbfc3824a758109c82ba..3ad93d63f6978b9cc587d5fbd5573e5f34cc991d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
@@ -27,7 +27,7 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 
-public interface RAbstractComplexVector extends RAbstractVector {
+public interface RAbstractComplexVector extends RAbstractAtomicVector {
 
     @Override
     default Object getDataAtAsObject(int index) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
index b8f4e98d3bdf472e95fe2c151483ba897b57194b..8bfd1573077131338384384b95014682a898dc7a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
@@ -27,7 +27,7 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 
-public interface RAbstractDoubleVector extends RAbstractVector {
+public interface RAbstractDoubleVector extends RAbstractAtomicVector {
 
     @Override
     default Object getDataAtAsObject(int index) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
index 739bbaad05205f33da7686e7159c9448d482334d..bc64990d6114804f91779463a367bd057c302b27 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
@@ -27,7 +27,7 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RInteger;
 
-public interface RAbstractIntVector extends RAbstractVector {
+public interface RAbstractIntVector extends RAbstractAtomicVector {
 
     @Override
     default Object getDataAtAsObject(int index) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
index 2203663c5e96c7578bb36ce11196477a6828ef52..abb58b0adb2308d62398abacb6137218b404d86e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
@@ -27,7 +27,7 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 
-public interface RAbstractLogicalVector extends RAbstractVector {
+public interface RAbstractLogicalVector extends RAbstractAtomicVector {
 
     @Override
     default Object getDataAtAsObject(int index) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
index c1a8873d8d2d1c767db50689d0f256255339dbd5..38441f5fb118b2c322746bf2f024ff842c49dec8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 
-public interface RAbstractRawVector extends RAbstractVector {
+public interface RAbstractRawVector extends RAbstractAtomicVector {
 
     @Override
     default Object getDataAtAsObject(int index) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
index c21728a8c03691497d98b912e40ab6b08feee290..032c8bed11216dd37a72c1670fc29b547e421436 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
@@ -27,7 +27,7 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
-public interface RAbstractStringVector extends RAbstractVector {
+public interface RAbstractStringVector extends RAbstractAtomicVector {
 
     @Override
     default Object getDataAtAsObject(int index) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
index fe950fa2a41f0ae9b4e6480338f82257e3ad64a9..29afedc8a40c5c747d5969575a8bcff44d5706af 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,55 +25,106 @@ package com.oracle.truffle.r.runtime.ffi;
 import java.io.IOException;
 import java.util.ArrayList;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+
 /**
  * A statically typed interface to exactly those native functions required by the R {@code base}
  * package, because the functionality is not provided by the JDK. These methods do not necessarily
  * map 1-1 to a native function, they may involve the invocation of several native functions.
  */
 public interface BaseRFFI {
-    int getpid();
+    abstract class GetpidNode extends Node {
+        public abstract int execute();
 
-    /**
-     * Returns the current working directory, in the face of calls to {@link #setwd}.
-     */
-    String getwd();
+        public static GetpidNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createGetpidNode();
+        }
+    }
 
-    /**
-     * Sets the current working directory to {@code dir}. (cf. Unix {@code chdir}).
-     *
-     * @return 0 if successful.
-     */
-    int setwd(String dir);
+    abstract class GetwdNode extends Node {
+        /**
+         * Returns the current working directory, in the face of calls to {@code setwd}.
+         */
+        public abstract String execute();
 
-    /**
-     * Create directory with given mode. Exception is thrown omn error.
-     */
-    void mkdir(String dir, int mode) throws IOException;
-
-    /**
-     * Try to convert a symbolic link to it's target.
-     *
-     * @param path the link path
-     * @return the target if {@code path} is a link else {@code null}
-     * @throws IOException for any other error except "not a link"
-     */
-    String readlink(String path) throws IOException;
+        public static GetwdNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createGetwdNode();
+        }
+    }
 
-    /**
-     * Creates a temporary directory using {@code template} and return the resulting path or
-     * {@code null} if error.
-     */
-    String mkdtemp(String template);
+    abstract class SetwdNode extends Node {
+        /**
+         * Sets the current working directory to {@code dir}. (cf. Unix {@code chdir}).
+         *
+         * @return 0 if successful.
+         */
+        public abstract int execute(String dir);
 
-    /**
-     * Change the file mode of {@code path}.
-     */
-    int chmod(String path, int mode);
+        public static SetwdNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createSetwdNode();
+        }
+    }
 
-    /**
-     * Convert string to long.
-     */
-    long strtol(String s, int base) throws IllegalArgumentException;
+    abstract class MkdirNode extends Node {
+        /**
+         * Create directory with given mode. Exception is thrown omn error.
+         */
+        public abstract void execute(String dir, int mode) throws IOException;
+
+        public static MkdirNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createMkdirNode();
+        }
+    }
+
+    abstract class ReadlinkNode extends Node {
+        /**
+         * Try to convert a symbolic link to it's target.
+         *
+         * @param path the link path
+         * @return the target if {@code path} is a link else {@code null}
+         * @throws IOException for any other error except "not a link"
+         */
+        public abstract String execute(String path) throws IOException;
+
+        public static ReadlinkNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createReadlinkNode();
+        }
+    }
+
+    abstract class MkdtempNode extends Node {
+        /**
+         * Creates a temporary directory using {@code template} and return the resulting path or
+         * {@code null} if error.
+         */
+        public abstract String execute(String template);
+
+        public static MkdtempNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createMkdtempNode();
+        }
+    }
+
+    abstract class ChmodNode extends Node {
+        /**
+         * Change the file mode of {@code path}.
+         */
+        public abstract int execute(String path, int mode);
+
+        public static ChmodNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createChmodNode();
+        }
+    }
+
+    abstract class StrolNode extends Node {
+        /**
+         * Convert string to long.
+         */
+        public abstract long execute(String s, int base) throws IllegalArgumentException;
+
+        public static StrolNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createStrolNode();
+        }
+    }
 
     public interface UtsName {
         String sysname();
@@ -87,14 +138,138 @@ public interface BaseRFFI {
         String nodename();
     }
 
-    /**
-     * Return {@code utsname} info.
+    abstract class UnameNode extends Node {
+        /**
+         * Return {@code utsname} info.
+         */
+        public abstract UtsName execute();
+
+        public static UnameNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createUnameNode();
+        }
+    }
+
+    abstract class GlobNode extends Node {
+        /**
+         * Returns an array of pathnames that match {@code pattern} using the OS glob function. This
+         * is done in native code because it is very hard to write in Java in the face of
+         * {@code setwd}.
+         */
+        public abstract ArrayList<String> glob(String pattern);
+
+        public static GlobNode create() {
+            return RFFIFactory.getRFFI().getBaseRFFI().createGlobNode();
+        }
+    }
+
+    /*
+     * The RFFI implementation influences exactly what subclass of the above nodes is created. Each
+     * implementation must therefore, implement these methods that are called by the associated
+     * "public static create()" methods above.
      */
-    UtsName uname();
 
-    /**
-     * Returns an array of pathnames that match {@code pattern} using the OS glob function. This is
-     * done in native code because it is very hard to write in Java in the face of {@link #setwd}.
+    GetpidNode createGetpidNode();
+
+    GetwdNode createGetwdNode();
+
+    SetwdNode createSetwdNode();
+
+    MkdirNode createMkdirNode();
+
+    ReadlinkNode createReadlinkNode();
+
+    MkdtempNode createMkdtempNode();
+
+    ChmodNode createChmodNode();
+
+    StrolNode createStrolNode();
+
+    UnameNode createUnameNode();
+
+    GlobNode createGlobNode();
+
+    /*
+     * Some functions are called from non-Truffle contexts, which requires a RootNode
      */
-    ArrayList<String> glob(String pattern);
+
+    final class GetpidRootNode extends RFFIRootNode<GetpidNode> {
+        private static GetpidRootNode getpidRootNode;
+
+        private GetpidRootNode() {
+            super(RFFIFactory.getRFFI().getBaseRFFI().createGetpidNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return rffiNode.execute();
+        }
+
+        public static GetpidRootNode create() {
+            if (getpidRootNode == null) {
+                getpidRootNode = new GetpidRootNode();
+            }
+            return getpidRootNode;
+        }
+    }
+
+    final class GetwdRootNode extends RFFIRootNode<GetwdNode> {
+        private static GetwdRootNode getwdRootNode;
+
+        private GetwdRootNode() {
+            super(RFFIFactory.getRFFI().getBaseRFFI().createGetwdNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return rffiNode.execute();
+        }
+
+        public static GetwdRootNode create() {
+            if (getwdRootNode == null) {
+                getwdRootNode = new GetwdRootNode();
+            }
+            return getwdRootNode;
+        }
+    }
+
+    final class MkdtempRootNode extends RFFIRootNode<MkdtempNode> {
+        private static MkdtempRootNode mkdtempRootNode;
+
+        private MkdtempRootNode() {
+            super(RFFIFactory.getRFFI().getBaseRFFI().createMkdtempNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return rffiNode.execute((String) args[0]);
+        }
+
+        public static MkdtempRootNode create() {
+            if (mkdtempRootNode == null) {
+                mkdtempRootNode = new MkdtempRootNode();
+            }
+            return mkdtempRootNode;
+        }
+    }
+
+    final class UnameRootNode extends RFFIRootNode<UnameNode> {
+        private static UnameRootNode unameRootNode;
+
+        private UnameRootNode() {
+            super(RFFIFactory.getRFFI().getBaseRFFI().createUnameNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return rffiNode.execute();
+        }
+
+        public static UnameRootNode create() {
+            if (unameRootNode == null) {
+                unameRootNode = new UnameRootNode();
+            }
+            return unameRootNode;
+        }
+    }
 }
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 e8f6e117dc99f28a7193e8c03c849a5072386021..8d0949631ee56fc97910b13fafdbb658d5434617 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,14 +28,14 @@ import com.oracle.truffle.api.nodes.Node;
  * Support for the {.C} and {.Fortran} calls.
  */
 public interface CRFFI {
-    abstract class CRFFINode extends Node {
+    abstract class InvokeCNode 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);
+        public abstract void execute(NativeCallInfo nativeCallInfo, Object[] args);
     }
 
-    CRFFINode createCRFFINode();
+    InvokeCNode createInvokeCNode();
 }
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 8620608493e7cdee94b262335f988a7db60b54f5..19de11e00e6a455f942f8dec4ed711f07faf0708 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,38 +22,76 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.data.RNull;
 
 /**
  * Support for the {.Call} and {.External} calls.
  */
 public interface CallRFFI {
-    abstract class CallRFFINode extends Node {
+    abstract class InvokeCallNode 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);
+        public abstract Object execute(NativeCallInfo nativeCallInfo, Object[] args);
+    }
 
+    abstract class InvokeVoidCallNode extends Node {
         /**
          * Variant that does not return a result (primarily for library "init" methods).
          */
-        public abstract void invokeVoidCall(NativeCallInfo nativeCallInfo, Object[] args);
+        public abstract void execute(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);
+    }
 
-        /**
-         * Sets the {@code R_Interactive} FFI variable. Similar rationale to {#link setTmpDir}.
-         */
-        public abstract void setInteractive(boolean interactive);
+    InvokeCallNode createInvokeCallNode();
+
+    InvokeVoidCallNode createInvokeVoidCallNode();
+
+    final class InvokeCallRootNode extends RFFIRootNode<InvokeCallNode> {
+        private static InvokeCallRootNode invokeCallRootNode;
+
+        private InvokeCallRootNode() {
+            super(RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return rffiNode.execute((NativeCallInfo) args[0], (Object[]) args[1]);
+        }
+
+        public static InvokeCallRootNode create() {
+            if (invokeCallRootNode == null) {
+                invokeCallRootNode = new InvokeCallRootNode();
+            }
+            return invokeCallRootNode;
+        }
     }
 
-    CallRFFINode createCallRFFINode();
+    final class InvokeVoidCallRootNode extends RFFIRootNode<InvokeVoidCallNode> {
+        private static InvokeVoidCallRootNode InvokeVoidCallRootNode;
+
+        private InvokeVoidCallRootNode() {
+            super(RFFIFactory.getRFFI().getCallRFFI().createInvokeVoidCallNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            rffiNode.execute((NativeCallInfo) args[0], (Object[]) args[1]);
+            return RNull.instance; // unused
+        }
+
+        public static InvokeVoidCallRootNode create() {
+            if (InvokeVoidCallRootNode == null) {
+                InvokeVoidCallRootNode = new InvokeVoidCallRootNode();
+            }
+            return InvokeVoidCallRootNode;
+        }
+    }
 
 }
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
index 161a93b520a4d41b676bf864830e1df530eb7461..62f5679c8c57b19df52ece5bb3f5ffcff0a08ffc 100644
--- 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
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.r.runtime.data.RTruffleObject;
+
 /**
  * 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
@@ -32,7 +34,7 @@ package com.oracle.truffle.r.runtime.ffi;
  * N.B. Use limited to RFFI implementations.
  *
  */
-public final class CharSXPWrapper {
+public final class CharSXPWrapper implements RTruffleObject {
     private final String contents;
 
     private CharSXPWrapper(String contents) {
@@ -48,7 +50,7 @@ public final class CharSXPWrapper {
         return "CHARSXP(" + contents + ")";
     }
 
-    public static Object create(String contents) {
+    public static CharSXPWrapper 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 6e8eee8c9bc69726d8e2173c57dd2f951f33056e..00825a42b45ddb1fd518cc46d09cd67265ba48aa 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
@@ -16,9 +16,14 @@ import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.frame.FrameDescriptor;
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.RErrorException;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -34,7 +39,8 @@ 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;
+import com.oracle.truffle.r.runtime.ffi.CallRFFI.InvokeVoidCallNode;
+import com.oracle.truffle.r.runtime.rng.user.UserRNG;
 
 /**
  * Support for Dynamically Loaded Libraries.
@@ -56,15 +62,18 @@ import com.oracle.truffle.r.runtime.ffi.CallRFFI.CallRFFINode;
  *
  * 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.
+ * always stored in slot 0 of the list, and is hidden from R code. It is loaded by {@link #loadLibR}
+ * , which should only be called once.
+ *
+ * As far as possible, all execution is via Truffle {@link Node} classes as, in most cases, the
+ * invocation is from an existing AST node.
  */
 public class DLL {
 
     public static class ContextStateImpl implements RContext.ContextState {
         private ArrayList<DLLInfo> list;
         private RContext context;
+        private static DLLInfo libRdllInfo;
 
         public static ContextStateImpl newContextState() {
             return new ContextStateImpl();
@@ -77,7 +86,10 @@ public class DLL {
                 list = context.getParent().stateDLL.list;
             } else {
                 list = new ArrayList<>();
-                list.add(libRDLLInfo);
+                if (!context.isInitial()) {
+                    assert list.isEmpty();
+                    list.add(libRdllInfo);
+                }
             }
             return this;
         }
@@ -87,11 +99,17 @@ public class DLL {
             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);
+                    DLLRFFI.DLCloseRootNode.create().getCallTarget().call(dllInfo.handle);
                 }
             }
             list = null;
         }
+
+        private void addLibR(DLLInfo dllInfo) {
+            assert list.isEmpty();
+            list.add(dllInfo);
+            libRdllInfo = dllInfo;
+        }
     }
 
     /**
@@ -345,56 +363,19 @@ public class DLL {
     }
 
     /**
-     * A temporary stash until such time as the initial context is initialized.
+     * Loads a the {@code libR} library. This is an implementation specific library.
      */
-    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 DLLInfo load(String path, boolean local, boolean now) throws DLLException {
-        String absPath = Utils.tildeExpand(path);
-        ContextStateImpl contextState = getContextState();
-        for (DLLInfo dllInfo : contextState.list) {
-            if (dllInfo.path.equals(absPath)) {
-                // already loaded
-                return dllInfo;
-            }
-        }
-        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 synchronized DLLInfo doLoad(String absPath, boolean local, boolean now, boolean addToList) throws DLLException {
-        Object handle = RFFIFactory.getRFFI().getDLLRFFI().dlopen(absPath, local, now);
+    public static void loadLibR(String path) {
+        RContext context = RContext.getInstance();
+        Object handle = DLLRFFI.DLOpenRootNode.create().getCallTarget().call(path, false, false);
         if (handle == null) {
-            String dlError = RFFIFactory.getRFFI().getDLLRFFI().dlerror();
-            if (RContext.isInitialContextInitialized()) {
-                throw new DLLException(RError.Message.DLL_LOAD_ERROR, absPath, dlError);
-            } else {
-                throw Utils.rSuicide("error loading default package: " + absPath + "\n" + dlError);
-            }
+            throw Utils.rSuicide("error loading libR from: " + path + "\n");
         }
-        DLLInfo dllInfo = DLLInfo.create(libName(absPath), absPath, true, handle, addToList);
-        return dllInfo;
+        ContextStateImpl dllContext = context.stateDLL;
+        dllContext.addLibR(DLLInfo.create(libName(path), path, true, handle, false));
     }
 
-    private static String libName(String absPath) {
+    public static String libName(String absPath) {
         File file = new File(absPath);
         String name = file.getName();
         int dx = name.lastIndexOf('.');
@@ -407,24 +388,36 @@ public class DLL {
     public static final String R_INIT_PREFIX = "R_init_";
 
     public static class LoadPackageDLLNode extends Node {
-        @Child private CallRFFINode callRFFINode;
+        @Child private InvokeVoidCallNode invokeVoidCallNode;
+        @Child private DLLRFFI.DLSymNode dlSymNode = RFFIFactory.getRFFI().getDLLRFFI().createDLSymNode();
+        @Child private DLLRFFI.DLOpenNode dlOpenNode = RFFIFactory.getRFFI().getDLLRFFI().createDLOpenNode();
 
         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
+        public DLLInfo execute(String path, boolean local, boolean now) throws DLLException {
+            String absPath = Utils.tildeExpand(path);
+            ContextStateImpl contextState = getContextState();
+            for (DLLInfo dllInfo : contextState.list) {
+                if (dllInfo.path.equals(absPath)) {
+                    // already loaded
+                    return dllInfo;
+                }
+            }
+            DLLInfo dllInfo = doLoad(absPath, local, now, true);
+
+            // Search for an init method
             String pkgInit = R_INIT_PREFIX + dllInfo.name;
-            SymbolHandle initFunc = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, pkgInit);
-            if (initFunc != SYMBOL_NOT_FOUND) {
+            try {
+                SymbolHandle initFunc = dlSymNode.execute(dllInfo.handle, pkgInit);
                 try {
-                    if (callRFFINode == null) {
-                        callRFFINode = insert(RFFIFactory.getRFFI().getCallRFFI().createCallRFFINode());
+                    if (invokeVoidCallNode == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        invokeVoidCallNode = insert(RFFIFactory.getRFFI().getCallRFFI().createInvokeVoidCallNode());
                     }
-                    callRFFINode.invokeVoidCall(new NativeCallInfo(pkgInit, initFunc, dllInfo), new Object[]{dllInfo});
+                    invokeVoidCallNode.execute(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
@@ -436,28 +429,64 @@ public class DLL {
                         throw Utils.rSuicide(RError.Message.DLL_RINIT_ERROR.message + " on default package: " + path);
                     }
                 }
+            } catch (UnsatisfiedLinkError ex) {
+                // no such symbol, that's ok
             }
             return dllInfo;
         }
+
+        /**
+         * 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 likely indicates a bug in the RFFI implementation. So we call
+         * {@link Utils#rSuicide(String)} 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 synchronized DLLInfo doLoad(String absPath, boolean local, boolean now, boolean addToList) throws DLLException {
+            try {
+                Object handle = dlOpenNode.execute(absPath, local, now);
+                DLLInfo dllInfo = DLLInfo.create(libName(absPath), absPath, true, handle, addToList);
+                return dllInfo;
+            } catch (UnsatisfiedLinkError ex) {
+                String dlError = ex.getMessage();
+                if (RContext.isInitialContextInitialized()) {
+                    throw new DLLException(RError.Message.DLL_LOAD_ERROR, absPath, dlError);
+                } else {
+                    throw Utils.rSuicide("error loading default package: " + absPath + "\n" + dlError);
+                }
+            }
+        }
+
     }
 
-    @TruffleBoundary
-    public static void unload(String path) throws DLLException {
-        String absPath = Utils.tildeExpand(path);
-        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, "");
+    public static class UnloadNode extends Node {
+        @Child private DLLRFFI.DLCloseNode dlCloseNode = RFFIFactory.getRFFI().getDLLRFFI().createDLCloseNode();
+
+        @TruffleBoundary
+        public void execute(String path) throws DLLException {
+            String absPath = Utils.tildeExpand(path);
+            ContextStateImpl contextState = getContextState();
+            for (DLLInfo info : contextState.list) {
+                if (info.path.equals(absPath)) {
+                    int rc = dlCloseNode.execute(info.handle);
+                    if (rc != 0) {
+                        throw new DLLException(RError.Message.DLL_LOAD_ERROR, path, "");
+                    }
+                    contextState.list.remove(info);
+                    return;
                 }
-                contextState.list.remove(info);
-                return;
             }
+            throw new DLLException(RError.Message.DLL_NOT_LOADED, path);
+        }
+
+        public static UnloadNode create() {
+            return new UnloadNode();
         }
-        throw new DLLException(RError.Message.DLL_NOT_LOADED, path);
     }
 
+    /**
+     * Returns the list of loaded DLLs in the current context.
+     */
     public static ArrayList<DLLInfo> getLoadedDLLs() {
         ArrayList<DLLInfo> result = new ArrayList<>();
         ContextStateImpl contextState = getContextState();
@@ -501,67 +530,133 @@ public class DLL {
         return SYMBOL_NOT_FOUND;
     }
 
-    /**
-     * Directly analogous to the GnuR function {@code R_dlsym}. Checks first for a
-     * {@link RegisteredNativeSymbol} using {@code rns}, then, unless dynamic lookup has been
-     * disabled, looks up the symbol using the {@code dlopen} machinery.
-     */
-    @TruffleBoundary
-    public static SymbolHandle dlsym(DLLInfo dllInfo, String name, RegisteredNativeSymbol rns) {
-        SymbolHandle f = getDLLRegisteredSymbol(dllInfo, name, rns);
-        if (f != SYMBOL_NOT_FOUND) {
-            return f;
-        }
+    public static final class RFindSymbolNode extends Node {
+        @Child RdlsymNode rdlsymNode = new RdlsymNode();
 
-        if (!dllInfo.dynamicLookup) {
+        /**
+         * Directly analogous to the GnuR function {@code R_FindSymbol}.
+         *
+         * @param name name of symbol (as appears in code) to look up
+         * @param libName name of library to restrict search to (or all if {@code null} or empty
+         *            string)
+         * @param rns {@code rns.nst} encodes the type of native symbol to restrict search to (or
+         *            all if {@code null})
+         */
+        @TruffleBoundary
+        public SymbolHandle execute(String name, String libName, RegisteredNativeSymbol rns) {
+            boolean all = libName == null || libName.length() == 0;
+            ContextStateImpl contextState = getContextState();
+            for (DLLInfo dllInfo : contextState.list) {
+                if (dllInfo.forceSymbols) {
+                    continue;
+                }
+                if (all || dllInfo.name.equals(libName)) {
+                    SymbolHandle func = rdlsymNode.execute(dllInfo, name, rns);
+                    if (func != SYMBOL_NOT_FOUND) {
+                        if (rns != null) {
+                            rns.dllInfo = dllInfo;
+                        }
+                        return func;
+                    }
+                }
+                if (!all && dllInfo.name.equals(libName)) {
+                    return SYMBOL_NOT_FOUND;
+                }
+            }
             return SYMBOL_NOT_FOUND;
         }
 
-        String mName = name;
-        // assume Fortran underscore, although GnuR has cc code for this
-        if (rns != null && rns.nst == NativeSymbolType.Fortran) {
-            mName = name + "_";
+        public static RFindSymbolNode create() {
+            return new RFindSymbolNode();
         }
-        SymbolHandle symValue = RFFIFactory.getRFFI().getDLLRFFI().dlsym(dllInfo.handle, mName);
-        if (symValue != null) {
-            return symValue;
-        } else {
-            return SYMBOL_NOT_FOUND;
+
+    }
+
+    private static final class RFindSymbolRootNode extends RootNode {
+        private static RFindSymbolRootNode findSymbolRootNode;
+
+        @Child RFindSymbolNode findSymbolNode = RFindSymbolNode.create();
+
+        private RFindSymbolRootNode() {
+            super(RContext.getRRuntimeASTAccess().getTruffleRLanguage(), null, new FrameDescriptor());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return findSymbolNode.execute((String) args[0], (String) args[1], (RegisteredNativeSymbol) args[2]);
+        }
+
+        private static RFindSymbolRootNode create() {
+            if (findSymbolRootNode == null) {
+                findSymbolRootNode = new RFindSymbolRootNode();
+                Truffle.getRuntime().createCallTarget(findSymbolRootNode);
+            }
+            return findSymbolRootNode;
         }
+
     }
 
-    /**
-     * Directly analogous to the GnuR function {@code R_FindSymbol}.
-     *
-     * @param name name of symbol (as appears in code) to look up
-     * @param libName name of library to restrict search to (or all if {@code null} or empty string)
-     * @param rns {@code rns.nst} encodes the type of native symbol to restrict search to (or all if
-     *            {@code null})
-     */
-    @TruffleBoundary
-    public static SymbolHandle findSymbol(String name, String libName, RegisteredNativeSymbol rns) {
-        boolean all = libName == null || libName.length() == 0;
-        ContextStateImpl contextState = getContextState();
-        for (DLLInfo dllInfo : contextState.list) {
-            if (dllInfo.forceSymbols) {
-                continue;
+    public static final class RdlsymNode extends Node {
+        @Child DLLRFFI.DLSymNode dlSymNode = RFFIFactory.getRFFI().getDLLRFFI().createDLSymNode();
+
+        /**
+         * Directly analogous to the GnuR function {@code R_dlsym}. Checks first for a
+         * {@link RegisteredNativeSymbol} using {@code rns}, then, unless dynamic lookup has been
+         * disabled, looks up the symbol using the {@code dlopen} machinery.
+         *
+         * N.B. Unlike the underlying {@link DLLRFFI.DLSymNode} node this does <b>not</b> throw
+         * {@link UnsatisfiedLinkError} if the symbol is not found; it returns
+         * {@link #SYMBOL_NOT_FOUND}.
+         */
+        @TruffleBoundary
+        public SymbolHandle execute(DLLInfo dllInfo, String name, RegisteredNativeSymbol rns) {
+            SymbolHandle f = getDLLRegisteredSymbol(dllInfo, name, rns);
+            if (f != SYMBOL_NOT_FOUND) {
+                return f;
             }
-            if (all || dllInfo.name.equals(libName)) {
-                SymbolHandle func = dlsym(dllInfo, name, rns);
-                if (func != SYMBOL_NOT_FOUND) {
-                    if (rns != null) {
-                        rns.dllInfo = dllInfo;
-                    }
-                    return func;
-                }
+
+            if (!dllInfo.dynamicLookup) {
+                return SYMBOL_NOT_FOUND;
+            }
+
+            String mName = name;
+            // assume Fortran underscore, although GnuR has cc code for this
+            if (rns != null && rns.nst == NativeSymbolType.Fortran) {
+                mName = name + "_";
             }
-            if (!all && dllInfo.name.equals(libName)) {
+            try {
+                SymbolHandle symValue = dlSymNode.execute(dllInfo.handle, mName);
+                return symValue;
+            } catch (UnsatisfiedLinkError ex) {
                 return SYMBOL_NOT_FOUND;
             }
         }
-        return SYMBOL_NOT_FOUND;
+
+        public static RdlsymNode create() {
+            return new RdlsymNode();
+        }
+    }
+
+    /**
+     * This is called by {@link UserRNG} because at the time the user-defined RNG is initialized it
+     * is not known which library defines the RNG symbols.
+     */
+    public static DLLInfo findLibraryContainingSymbol(String symbol) {
+        RegisteredNativeSymbol rns = RegisteredNativeSymbol.any();
+        SymbolHandle func = (SymbolHandle) RFindSymbolRootNode.create().getCallTarget().call(symbol, null, rns);
+        if (func == SYMBOL_NOT_FOUND) {
+            return null;
+        } else {
+            return rns.dllInfo;
+        }
     }
 
+    /**
+     * Searches the loaded libraries (packages) in this context for one that matches {@code name}.,
+     * where {@code name} should be equivalent to having called {@link #libName} on the path to the
+     * library.
+     */
     public static DLLInfo findLibrary(String name) {
         ContextStateImpl contextState = getContextState();
         for (DLLInfo dllInfo : contextState.list) {
@@ -572,14 +667,16 @@ public class DLL {
         return null;
     }
 
-    @TruffleBoundary
-    public static DLLInfo findLibraryContainingSymbol(String symbol) {
-        RegisteredNativeSymbol rns = RegisteredNativeSymbol.any();
-        SymbolHandle func = findSymbol(symbol, null, rns);
-        if (func == SYMBOL_NOT_FOUND) {
-            return null;
+    /**
+     * Search for symbol {@code name} in library defined by {@code dllInfo}, or {@code null} for
+     * search in all loaded libraries. Used in the rare cases where no Truffle execution context
+     * available.
+     */
+    public static SymbolHandle findSymbol(String name, DLLInfo dllInfo) {
+        if (dllInfo != null) {
+            return (SymbolHandle) DLLRFFI.DLSymRootNode.create().getCallTarget().call(dllInfo.handle, name);
         } else {
-            return rns.dllInfo;
+            return (SymbolHandle) RFindSymbolRootNode.create().getCallTarget().call(name, null, RegisteredNativeSymbol.any());
         }
     }
 
@@ -609,4 +706,5 @@ public class DLL {
         }
         return result;
     }
+
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java
index 09e61c5bb0bb1d7d8122caf034cd3d04ee34f047..fecf157ec83894882d71052ca23f81d31f587cf8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLLRFFI.java
@@ -22,40 +22,118 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 
-/**
- * Caller should not assume that this interface is implemented in a thread-safe manner. In
- * particular, pairs of {@link #dlopen}/{@link #dlerror} and {@link #dlsym}/{@link #dlerror} should
- * be atomic in the caller.
- *
- */
 public interface DLLRFFI {
-    /**
-     * Open a DLL.
-     *
-     * @return {@code null} on error, opaque handle for following calls otherwise.
-     */
-    Object dlopen(String path, boolean local, boolean now);
-
-    /**
-     * Search for {@code symbol} in DLL specified by {@code handle}. To accommodate differing
-     * implementations of this interface the result is {@link SymbolHandle}. For the standard OS
-     * implementation this will encapsulate a {@link Long} or {@code null} if an error occurred.
-     *
-     */
-    SymbolHandle dlsym(Object handle, String symbol);
-
-    /**
-     * Close DLL specified by {@code handle}.
-     */
-    int dlclose(Object handle);
-
-    /**
-     * Get any error message.
-     *
-     * @return {@code null} if no error, message otherwise.
-     */
-    String dlerror();
+    abstract class DLOpenNode extends Node {
+        /**
+         * Open a DLL.
+         *
+         * @return {@code null} on error, opaque handle for following calls otherwise.
+         */
+        public abstract Object execute(String path, boolean local, boolean now) throws UnsatisfiedLinkError;
+
+        public static DLOpenNode create() {
+            return RFFIFactory.getRFFI().getDLLRFFI().createDLOpenNode();
+        }
+    }
+
+    abstract class DLSymNode extends Node {
+        /**
+         * Search for {@code symbol} in DLL specified by {@code handle}. To accommodate differing
+         * implementations of this interface the result is {@link SymbolHandle}. For the standard OS
+         * implementation this will encapsulate a {@link Long} or {@code null} if an error occurred.
+         *
+         */
+        public abstract SymbolHandle execute(Object handle, String symbol) throws UnsatisfiedLinkError;
+
+        public static DLSymNode create() {
+            return RFFIFactory.getRFFI().getDLLRFFI().createDLSymNode();
+        }
+    }
+
+    abstract class DLCloseNode extends Node {
+        /**
+         * Close DLL specified by {@code handle}.
+         */
+        public abstract int execute(Object handle);
+
+        public static DLCloseNode create() {
+            return RFFIFactory.getRFFI().getDLLRFFI().createDLCloseNode();
+        }
+    }
+
+    DLOpenNode createDLOpenNode();
+
+    DLSymNode createDLSymNode();
+
+    DLCloseNode createDLCloseNode();
+
+    // RootNodes
+
+    final class DLOpenRootNode extends RFFIRootNode<DLOpenNode> {
+        private static DLOpenRootNode dlOpenRootNode;
+
+        private DLOpenRootNode() {
+            super(RFFIFactory.getRFFI().getDLLRFFI().createDLOpenNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return rffiNode.execute((String) args[0], (boolean) args[1], (boolean) args[2]);
+        }
+
+        public static DLOpenRootNode create() {
+            if (dlOpenRootNode == null) {
+                dlOpenRootNode = new DLOpenRootNode();
+            }
+            return dlOpenRootNode;
+        }
+    }
+
+    final class DLSymRootNode extends RFFIRootNode<DLSymNode> {
+        private static DLSymRootNode dlSymRootNode;
+
+        private DLSymRootNode() {
+            super(RFFIFactory.getRFFI().getDLLRFFI().createDLSymNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return rffiNode.execute(args[0], (String) args[1]);
+        }
+
+        public static DLSymRootNode create() {
+            if (dlSymRootNode == null) {
+                dlSymRootNode = new DLSymRootNode();
+            }
+            return dlSymRootNode;
+        }
+    }
+
+    final class DLCloseRootNode extends RFFIRootNode<DLCloseNode> {
+        private static DLCloseRootNode dlCloseRootNode;
+
+        private DLCloseRootNode() {
+            super(RFFIFactory.getRFFI().getDLLRFFI().createDLCloseNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return rffiNode.execute(args[0]);
+        }
+
+        public static DLCloseRootNode create() {
+            if (dlCloseRootNode == null) {
+                dlCloseRootNode = new DLCloseRootNode();
+            }
+            return dlCloseRootNode;
+        }
+    }
 
 }
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
deleted file mode 100644
index 5985c20786ce0077477c5822c4dad0d98b5b987d..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIRootNode.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.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 9d410b1054b72fa146627a30012e09c103dbdcc8..43082161ce14e5abaca49d55af3ce7b998993ad2 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,11 +26,24 @@ import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 public interface GridRFFI {
-    abstract class GridRFFINode extends Node {
-        public abstract Object initGrid(REnvironment gridEvalEnv);
+    abstract class InitGridNode extends Node {
+        public abstract Object execute(REnvironment gridEvalEnv);
 
-        public abstract Object killGrid();
+        public static InitGridNode create() {
+            return RFFIFactory.getRFFI().getGridRFFI().createInitGridNode();
+        }
     }
 
-    GridRFFINode createGridRFFINode();
+    abstract class KillGridNode extends Node {
+
+        public abstract Object execute();
+
+        public static KillGridNode create() {
+            return RFFIFactory.getRFFI().getGridRFFI().createKillGridNode();
+        }
+    }
+
+    InitGridNode createInitGridNode();
+
+    KillGridNode createKillGridNode();
 }
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/IDEUpCallsRFFI.java
similarity index 59%
rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UpCallsRFFIFactory.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/IDEUpCallsRFFI.java
index ad90095e5d43c62b89736d67dc05c0a60d035c1a..4ba0c703c77784c6108895f7a40f0ea9c0acfd85 100644
--- 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/IDEUpCallsRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,23 +22,30 @@
  */
 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);
-        }
-    }
+import com.oracle.truffle.api.frame.Frame;
 
-    private static UpCallsRFFIFactory theInstance;
+/**
+ * Additional upcalls created for supporting FastR in RStudio. These mainly relate to the GNU R
+ * notion of a "context", which corresponds somewhat to a Truffle {@link Frame}.
+ */
+public interface IDEUpCallsRFFI {
+    // Checkstyle: stop method name check
+    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();
 
-    public static UpCallsRFFIFactory getInstance() {
-        return theInstance;
-    }
+    int R_isGlobal(Object c);
 
-    public abstract UpCallsRFFI getUpcallsRFFI();
+    int R_isEqual(Object x, Object y);
 
 }
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 cff6aadebf60cdce9f6b0f3aa44fd5789218a020..c963ab2ec8ff7385eb2d5eb97d09196fab53f23b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/PCRERFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/PCRERFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,21 +49,67 @@ public interface PCRERFFI {
         }
     }
 
-    abstract class PCRERFFINode extends Node {
+    abstract class MaketablesNode extends Node {
 
-        public abstract long maketables();
+        public abstract long execute();
 
-        public abstract Result compile(String pattern, int options, long tables);
+        public static MaketablesNode create() {
+            return RFFIFactory.getRFFI().getPCRERFFI().createMaketablesNode();
+        }
+    }
+
+    abstract class CompileNode extends Node {
+
+        public abstract Result execute(String pattern, int options, long tables);
+
+        public static CompileNode create() {
+            return RFFIFactory.getRFFI().getPCRERFFI().createCompileNode();
+        }
+    }
+
+    abstract class GetCaptureCountNode extends Node {
+
+        public abstract int execute(long code, long extra);
+
+        public static GetCaptureCountNode create() {
+            return RFFIFactory.getRFFI().getPCRERFFI().createGetCaptureCountNode();
+        }
+    }
 
-        public abstract int getCaptureCount(long code, long extra);
+    abstract class GetCaptureNamesNode extends Node {
+        public abstract String[] execute(long code, long extra, int captureCount);
 
-        public abstract String[] getCaptureNames(long code, long extra, int captureCount);
+        public static GetCaptureNamesNode create() {
+            return RFFIFactory.getRFFI().getPCRERFFI().createGetCaptureNamesNode();
+        }
+    }
+
+    abstract class StudyNode extends Node {
+        public abstract Result execute(long code, int options);
+
+        public static StudyNode create() {
+            return RFFIFactory.getRFFI().getPCRERFFI().createStudyNode();
+        }
+    }
 
-        public abstract Result study(long code, int options);
+    abstract class ExecNode extends Node {
+        public abstract int execute(long code, long extra, String subject, int offset, int options, int[] ovector);
 
-        public abstract int exec(long code, long extra, String subject, int offset, int options, int[] ovector);
+        public static ExecNode create() {
+            return RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
+        }
     }
 
-    PCRERFFINode createPCRERFFINode();
+    MaketablesNode createMaketablesNode();
+
+    CompileNode createCompileNode();
+
+    GetCaptureCountNode createGetCaptureCountNode();
+
+    GetCaptureNamesNode createGetCaptureNamesNode();
+
+    StudyNode createStudyNode();
+
+    ExecNode createExecNode();
 
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/truffle/TruffleRFFIFrameHelper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RContextUpCallsRFFI.java
similarity index 64%
rename from com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/truffle/TruffleRFFIFrameHelper.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RContextUpCallsRFFI.java
index 6b892a78508eb4b640a63e20b5836ba5136b4718..ab6621014ff9c789c161a5640fa6522b3799b75d 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/truffle/TruffleRFFIFrameHelper.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RContextUpCallsRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,14 +20,25 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.runtime.ffi.truffle;
+package com.oracle.truffle.r.runtime.ffi;
 
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
-import com.oracle.truffle.r.runtime.Utils;
+/**
+ * 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.
+ */
+
+public interface RContextUpCallsRFFI {
+    // Checkstyle: stop method name check
+    Object R_GlobalContext();
+
+    Object R_GlobalEnv();
+
+    Object R_BaseEnv();
+
+    Object R_BaseNamespace();
+
+    Object R_NamespaceRegistry();
+
+    int R_Interactive();
 
-public class TruffleRFFIFrameHelper {
-    public static VirtualFrame create() {
-        return SubstituteVirtualFrame.create(Utils.getActualCurrentFrame().materialize());
-    }
 }
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java
similarity index 76%
rename from com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFIFactory.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java
index 6bf0183d8e85302127526f6631c99f81662030f6..c8dbee39e12f83ea246b81d120268560bb150ae7 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFIFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java
@@ -22,10 +22,16 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
-public class JavaUpCallsRFFIFactory extends UpCallsRFFIFactory {
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Tags an upcall argument as being (on the native side) a C string.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+public @interface RFFICstring {
 
-    @Override
-    public UpCallsRFFI getUpcallsRFFI() {
-        return new JavaUpCallsRFFI();
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
index fa9895000472ac2ffc16396c3cd140d257e334d7..35fdd63dac7b346cfd6cdcb1f1b73c76c890b90c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,24 +23,45 @@
 package com.oracle.truffle.r.runtime.ffi;
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 
 /**
- * Factory class for the different possible implementations of the {@link RFFI} interface. The
- * choice of factory is made by the R engine and set here by the call to {@link #setRFFIFactory}.
+ * Factory class for the different possible implementations of the {@link RFFI} interface.
  *
  * The RFFI may need to do special things in the case of multiple contexts, hence any given factory
- * must support the {@link #newContextState()} method. However, since we don't know exactly which
- * factory will be used, {@link RContext} references the {@link RFFIContextStateFactory} class.
+ * must support the {@link #newContextState()} method.
  */
 public abstract class RFFIFactory {
+    private static final String FACTORY_CLASS_PROPERTY = "fastr.ffi.factory.class";
+    private static final String DEFAULT_FACTORY_CLASS = "com.oracle.truffle.r.runtime.ffi.jni.JNI_RFFIFactory";
+
+    /**
+     * Singleton instance of the factory.
+     */
+    private static RFFIFactory instance;
 
     @CompilationFinal protected static RFFI theRFFI;
 
-    public static void setRFFIFactory(RFFIFactory factory) {
-        RFFIContextStateFactory.registerFactory(factory);
-        theRFFI = factory.createRFFI();
+    public static RFFIFactory initialize() {
+        if (instance == null) {
+            String prop = System.getProperty(FACTORY_CLASS_PROPERTY);
+            try {
+                if (prop == null) {
+                    prop = DEFAULT_FACTORY_CLASS;
+                }
+                instance = (RFFIFactory) Class.forName(prop).newInstance();
+                theRFFI = instance.createRFFI();
+            } catch (Exception ex) {
+                throw Utils.rSuicide("Failed to instantiate class: " + prop + ": " + ex);
+            }
+        }
+        return instance;
+    }
+
+    public static RFFIFactory getInstance() {
+        assert instance != null;
+        return instance;
     }
 
     public static RFFI getRFFI() {
@@ -48,18 +69,6 @@ public abstract class RFFIFactory {
         return theRFFI;
     }
 
-    /**
-     * Initialize the factory instance. This method will be called immediately after the factory
-     * instance is created allowing any additional initialization that could not be done in the
-     * constructor.
-     *
-     * @param runtime {@code true} if the initialization is being done at runtime. An AOT system may
-     *            call this twice, once with {@code false} whern an image is being bilt and once
-     *            when starting up.
-     */
-    protected void initialize(boolean runtime) {
-    }
-
     /**
      * Subclass implements this method to actually create the concrete {@link RFFI} instance.
      */
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIRootNode.java
similarity index 63%
rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java
rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIRootNode.java
index 934ad58e5ef650278cab6880dc4afc692cf5c19a..71d8f98278e42b662db1ed71c61af3c27d70ff00 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIRootNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,22 +22,19 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.FrameDescriptor;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.context.RContext.ContextState;
 
-/**
- * This is the factory-independent class referenced by {@link RContext} that manages the
- * context-specific state for any given {@link RFFIFactory}. It simply forwards the calls to the
- * actual factory.
- */
-public class RFFIContextStateFactory {
-    private static RFFIFactory theFactory;
+public abstract class RFFIRootNode<T extends Node> extends RootNode {
+    @Child T rffiNode;
 
-    public static void registerFactory(RFFIFactory factory) {
-        theFactory = factory;
+    protected RFFIRootNode(T baseRFFINode) {
+        super(RContext.getRRuntimeASTAccess().getTruffleRLanguage(), null, new FrameDescriptor());
+        this.rffiNode = baseRFFINode;
+        Truffle.getRuntime().createCallTarget(this);
     }
 
-    public static ContextState newContextState() {
-        return theFactory.newContextState();
-    }
 }
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 67adab0639211e28786f15af9be6578e12abcdb6..d1dcd13fc0be31779570e816926bfa3cf6b1d3e3 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, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,12 +30,24 @@ import com.oracle.truffle.api.nodes.Node;
  * {@code fft_factor} and {@code fft_work}. functions from the GNU R C code.
  */
 public interface StatsRFFI {
-    abstract class FFTNode extends Node {
-        public abstract void executeFactor(int n, int[] pmaxf, int[] pmaxp);
+    abstract class FactorNode extends Node {
+        public abstract void execute(int n, int[] pmaxf, int[] pmaxp);
 
-        public abstract int executeWork(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork);
+        public static FactorNode create() {
+            return RFFIFactory.getRFFI().getStatsRFFI().createFactorNode();
+        }
     }
 
-    FFTNode createFFTNode();
+    abstract class WorkNode extends Node {
+        public abstract int execute(double[] a, int nseg, int n, int nspn, int isn, double[] work, int[] iwork);
+
+        public static WorkNode create() {
+            return RFFIFactory.getRFFI().getStatsRFFI().createWorkNode();
+        }
+    }
+
+    FactorNode createFactorNode();
+
+    WorkNode createWorkNode();
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d96124a1cae1cfce8e8af31608e92dd60bbc9a6
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.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.
+ *
+ * N.B. It is important not to be too specific about types owing the support for Truffle interop
+ * implementations. For example, many arguments are "strings" but we do not specify them as
+ * {@code String} here.
+ */
+public interface StdUpCallsRFFI {
+    // 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_coerceVector(Object x, int mode);
+
+    Object Rf_mkCharLenCE(@RFFICstring Object bytes, int len, int encoding);
+
+    Object Rf_cons(Object car, Object cdr);
+
+    void Rf_defineVar(Object symbolArg, Object value, Object envArg);
+
+    Object R_do_MAKE_CLASS(@RFFICstring Object 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(@RFFICstring Object x, Object clazz);
+
+    Object Rf_install(@RFFICstring Object 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(@RFFICstring Object msg);
+
+    void Rf_warning(@RFFICstring Object msg);
+
+    void Rf_warningcall(Object call, @RFFICstring Object 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 IS_S4_OBJECT(Object x);
+
+    void Rprintf(@RFFICstring Object 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, int initialSize);
+
+    int PRSEEN(Object x);
+
+    Object PRENV(Object x);
+
+    Object R_PromiseExpr(Object x);
+
+    Object PRCODE(Object x);
+
+    Object R_CHAR(Object x);
+
+}
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 290daad5f02a030ce1c177c3b461f7332fb3fae4..7d797e62f112dfb5f13ca953d802bd2c0f3086d2 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ToolsRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ToolsRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  * Interface to native (C) methods provided by the {@code tools} package.
  */
 public interface ToolsRFFI {
-    abstract class ToolsRFFINode extends Node {
+    abstract class ParseRdNode 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, ...)}
@@ -41,9 +41,9 @@ public interface ToolsRFFI {
          * code. We can't go straight to the GnuR C entry point as that makes GnuR-specific
          * assumptions about, for example, how connections are implemented.
          */
-        public abstract Object parseRd(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
+        public abstract Object execute(RConnection con, REnvironment srcfile, RLogicalVector verbose, RLogicalVector fragment, RStringVector basename, RLogicalVector warningCalls, Object macros,
                         RLogicalVector warndups);
     }
 
-    ToolsRFFINode createToolsRFFINode();
+    ParseRdNode createParseRdNode();
 }
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
index ccfb5fa901804eb5d13cc1f0858d736fe1c0cc4d..563e8ca60fb3a7bf122d23cb48fed89fe816f686 100644
--- 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,258 +22,9 @@
  */
 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.
- *
+ * Aggregation of all the FFI upcall interfaces.
  */
-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);
+public interface UpCallsRFFI extends StdUpCallsRFFI, RContextUpCallsRFFI, IDEUpCallsRFFI {
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java
index dc99a9ddb7a8e116cb0023e4084e7f45b16f82e1..1eecb127e95bfe8e20a69978b753c93811f79a2b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/ZipRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,21 +22,82 @@
  */
 package com.oracle.truffle.r.runtime.ffi;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+
+/**
+ * zip compression/uncompression.
+ */
 public interface ZipRFFI {
-    // zip compression/uncompression
-
-    /**
-     * compress {@code source} into {@code dest}.
-     *
-     * @return standard return code (0 ok)
-     */
-    int compress(byte[] dest, byte[] source);
-
-    /**
-     * uncompress {@code source} into {@code dest}.
-     *
-     * @return standard return code (0 ok)
-     */
-    int uncompress(byte[] dest, byte[] source);
+
+    abstract class CompressNode extends Node {
+        /**
+         * compress {@code source} into {@code dest}.
+         *
+         * @return standard return code (0 ok)
+         */
+        public abstract int execute(byte[] dest, byte[] source);
+
+        public static CompressNode create() {
+            return RFFIFactory.getRFFI().getZipRFFI().createCompressNode();
+        }
+    }
+
+    abstract class UncompressNode extends Node {
+        /**
+         * uncompress {@code source} into {@code dest}.
+         *
+         * @return standard return code (0 ok)
+         */
+        public abstract int execute(byte[] dest, byte[] source);
+    }
+
+    CompressNode createCompressNode();
+
+    UncompressNode createUncompressNode();
+
+    // RootNodes for calling when not in Truffle context
+
+    final class CompressRootNode extends RFFIRootNode<CompressNode> {
+        private static CompressRootNode compressRootNode;
+
+        private CompressRootNode() {
+            super(RFFIFactory.getRFFI().getZipRFFI().createCompressNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return rffiNode.execute((byte[]) args[0], (byte[]) args[1]);
+        }
+
+        public static CompressRootNode create() {
+            if (compressRootNode == null) {
+                compressRootNode = new CompressRootNode();
+            }
+            return compressRootNode;
+        }
+    }
+
+    final class UncompressRootNode extends RFFIRootNode<UncompressNode> {
+        private static UncompressRootNode uncompressRootNode;
+
+        private UncompressRootNode() {
+            super(RFFIFactory.getRFFI().getZipRFFI().createUncompressNode());
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] args = frame.getArguments();
+            return rffiNode.execute((byte[]) args[0], (byte[]) args[1]);
+        }
+
+        public static UncompressRootNode create() {
+            if (uncompressRootNode == null) {
+                uncompressRootNode = new UncompressRootNode();
+            }
+            return uncompressRootNode;
+        }
+    }
 
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java
index 2735f2873b6f49f1e2e17099f5e8513eebd3d60b..4740bd9bc7c7364e73f758441c9621f7c8a45a30 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -157,8 +157,15 @@ public enum SEXPTYPE {
      * Accessed from FFI layer.
      */
     public static int gnuRCodeForObject(Object obj) {
+        return gnuRTypeForObject(obj).code;
+    }
+
+    /**
+     * Accessed from FFI layer.
+     */
+    public static SEXPTYPE gnuRTypeForObject(Object obj) {
         SEXPTYPE type = typeForClass(obj.getClass());
-        return gnuRType(type, obj).code;
+        return gnuRType(type, obj);
     }
 
     /**
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java
index d4f9f6d33c68d82e1d813a62862225fe89da029e..730c1b5a772da628f5e7e2e44c66b5191f2aad91 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java
@@ -140,6 +140,17 @@ public abstract class RBaseNode extends Node {
         Node current = this;
         while (current != null) {
             if (current instanceof RSyntaxNode && ((RSyntaxNode) current).isSyntax()) {
+                if (current instanceof RSyntaxCall) {
+                    RSyntaxCall call = (RSyntaxCall) current;
+                    if (call.getSyntaxArguments().length > 0 && call.getSyntaxLHS() instanceof RSyntaxLookup &&
+                                    ((RSyntaxLookup) call.getSyntaxLHS()).getIdentifier().equals(".Internal")) {
+                        // unwrap .Internal calls
+                        RSyntaxElement firstArg = call.getSyntaxArguments()[0];
+                        if (firstArg instanceof RSyntaxNode) {
+                            return (RSyntaxNode) firstArg;
+                        }
+                    }
+                }
                 return (RSyntaxNode) current;
             }
             current = current.getParent();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
index c07a69b8732adb872af3e47997557920784ccb4e..8629846c531dd5fd14686a5db6e21db3d9abf77f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
@@ -63,17 +63,28 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 @Instrumentable(factory = com.oracle.truffle.r.runtime.nodes.instrumentation.RNodeWrapperFactory.class)
 public abstract class RNode extends RBaseNode implements RInstrumentableNode {
 
+    /**
+     * Normal execute function that is called when the return value, but not its visibility is
+     * needed.
+     */
     public abstract Object execute(VirtualFrame frame);
 
     /**
-     * This function can be called when the result is not needed, and normally just dispatches to
-     * {@link #execute(VirtualFrame)}. Its name does not start with "execute" so that the DSL does
-     * not treat it like an execute function.
+     * This function is called when the result is not needed. Its name does not start with "execute"
+     * so that the DSL does not treat it like an execute function.
      */
     public void voidExecute(VirtualFrame frame) {
         execute(frame);
     }
 
+    /**
+     * This function is called when both the result and the result's visibility are needed. Its name
+     * does not start with "execute" so that the DSL does not treat it like an execute function.
+     */
+    public Object visibleExecute(VirtualFrame frame) {
+        return execute(frame);
+    }
+
     public int executeInteger(VirtualFrame frame) throws UnexpectedResultException {
         Object value = execute(frame);
         assert value != null;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java
index d79719b63ea8d8b382b74ae6d3ef9baabcf49aac..b385fc6fe9e9e4f4e5d4c02a47eafeed9e53ae18 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,6 +80,19 @@ public final class RNodeWrapperFactory implements InstrumentableFactory<RNode> {
             }
         }
 
+        @Override
+        public Object visibleExecute(VirtualFrame frame) {
+            try {
+                probeNode.onEnter(frame);
+                Object returnValue = delegate.visibleExecute(frame);
+                probeNode.onReturnValue(frame, returnValue);
+                return returnValue;
+            } catch (Throwable t) {
+                probeNode.onReturnExceptional(frame, t);
+                throw t;
+            }
+        }
+
         @Override
         public RSyntaxNode getRSyntaxNode() {
             return delegate.asRSyntaxNode();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
index 7ab4c8007bc955514a23a30604fd170cedddcd11..db3f531e93a4643264ef25d0b473c6eb5a429035 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
@@ -25,7 +25,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.env.REnvironment;
-import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.rng.mm.MarsagliaMulticarry;
 import com.oracle.truffle.r.runtime.rng.mt.MersenneTwister;
 import com.oracle.truffle.r.runtime.rng.user.UserRNG;
@@ -294,7 +294,7 @@ public class RRNG {
      * Create a random integer.
      */
     public static Integer timeToSeed() {
-        int pid = RFFIFactory.getRFFI().getBaseRFFI().getpid();
+        int pid = (int) BaseRFFI.GetpidRootNode.create().getCallTarget().call();
         int millis = (int) (System.currentTimeMillis() & 0xFFFFFFFFL);
         return (millis << 16) ^ pid;
     }
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 599d905eb34d8ad18c977fbd2b17d26992d600fd..93c1f237119fd4495b9a25e4d2310629f79cd5e3 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
@@ -147,7 +147,7 @@ public final class UserRNG implements RandomNumberGenerator {
     }
 
     private static DLL.SymbolHandle findSymbol(String symbol, DLLInfo dllInfo, boolean optional) {
-        DLL.SymbolHandle func = DLL.findSymbol(symbol, dllInfo.name, DLL.RegisteredNativeSymbol.any());
+        DLL.SymbolHandle func = DLL.findSymbol(symbol, dllInfo);
         if (func == DLL.SYMBOL_NOT_FOUND) {
             if (!optional) {
                 throw RError.error(RError.NO_CALLER, RError.Message.RNG_SYMBOL, symbol);
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 48d34db470d1bc751044c3411b51a433f78c5d02..93443593a81e7a51e33ea5635caad97d4aff06e2 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
@@ -125,4 +125,34 @@ rffi.null.C <- function() {
 	.Call(C_null)
 }
 
+rffi.asReal <- function(x) {
+	.Call("test_asReal", x)
+}
+
+rffi.asInteger <- function(x) {
+	.Call("test_asInteger", x)
+}
+
+rffi.asLogical <- function(x) {
+	.Call("test_asLogical", x)
+}
+
+rffi.asChar <- function(x) {
+	.Call("test_asChar", x)
+}
 
+rffi.CAR <- function(x) {
+	.Call("test_CAR", x)
+}
+
+rffi.CDR <- function(x) {
+	.Call("test_CDR", x)
+}
+
+rffi.LENGTH <- function(x) {
+	.Call("test_LENGTH", x)
+}
+
+rffi.coerceVector <- function(x, mode) {
+	.Call("test_coerceVector", x, mode)
+}
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 5af8e6bb9f7b8298be0b5a6ee5a99fafd51ffe25..cf78dd91c91aba55acf21084125944ee749566bd 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, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,32 +33,40 @@ static const R_CMethodDef CEntries[]  = {
 #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}
+        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),
+        CALLDEF(test_asReal, 1),
+        CALLDEF(test_asChar, 1),
+        CALLDEF(test_asInteger, 1),
+        CALLDEF(test_asLogical, 1),
+        CALLDEF(test_CAR, 1),
+        CALLDEF(test_CDR, 1),
+        CALLDEF(test_LENGTH, 1),
+        CALLDEF(test_coerceVector, 2),
+        {NULL, NULL, 0}
 };
 
 void
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 b8f04f014f1932f69092eaeda8e7e26737c065e7..364653bd0d88d9e00c2bf5d8f42d489068749663 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -290,3 +290,36 @@ SEXP findvar(SEXP x, SEXP env) {
 	}
 }
 
+SEXP test_asReal(SEXP x) {
+	return Rf_ScalarReal(Rf_asReal(x));
+}
+
+SEXP test_asInteger(SEXP x) {
+	return Rf_ScalarInteger(Rf_asInteger(x));
+}
+
+SEXP test_asLogical(SEXP x) {
+	return Rf_ScalarLogical(Rf_asLogical(x));
+}
+
+SEXP test_asChar(SEXP x) {
+	return Rf_ScalarString(Rf_asChar(x));
+}
+
+SEXP test_CAR(SEXP x) {
+	return CAR(x);
+}
+
+SEXP test_CDR(SEXP x) {
+	return CDR(x);
+}
+
+SEXP test_LENGTH(SEXP x) {
+	return ScalarInteger(LENGTH(x));
+}
+
+SEXP test_coerceVector(SEXP x, SEXP mode) {
+    int intMode = INTEGER_VALUE(mode);
+    return Rf_coerceVector(x, intMode);
+}
+
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
index 44de64f3dacf7f6b4dcda78ca61fe0ab4b58eff2..1787b056454851783af719ead163b9b21f1aab60 100644
--- 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,3 +71,20 @@ extern SEXP preserve_object(void);
 extern SEXP release_object(SEXP x);
 
 extern SEXP findvar(SEXP x, SEXP env);
+
+extern SEXP test_asReal(SEXP x);
+
+extern SEXP test_asChar(SEXP x);
+
+extern SEXP test_asInteger(SEXP x);
+
+extern SEXP test_asLogical(SEXP x);
+
+extern SEXP test_CAR(SEXP x);
+
+extern SEXP test_CDR(SEXP x);
+
+extern SEXP test_LENGTH(SEXP x);
+
+extern SEXP test_coerceVector(SEXP x, SEXP mode);
+
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 ce4e31970c1c8b676edc3d5efb2b65ba18b0450b..366264daa34980cb3909e3aed54f68207321fb9f 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
@@ -5466,7 +5466,7 @@ character(0)
 #argv <- list(list(epsilon = 1e-08, maxit = 25, trace = FALSE));as.character(argv[[1]]);
 [1] "1e-08" "25"    "FALSE"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testascharacter19#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testascharacter19#
 #argv <- list(structure(list(structure(list(given = c('George', 'E.', 'P.'), family = 'Box', role = NULL, email = NULL, comment = NULL), .Names = c('given', 'family', 'role', 'email', 'comment')), structure(list(given = c('David', 'R.'), family = 'Cox', role = NULL, email = NULL, comment = NULL), .Names = c('given', 'family', 'role', 'email', 'comment'))), class = 'person'));as.character(argv[[1]]);
 [1] "George E. P. Box" "David R. Cox"
 
@@ -5577,7 +5577,7 @@ character(0)
 [4] "2012-06-04 04:00:00" "2012-06-05 04:00:00" "2012-06-06 04:00:00"
 [7] "2012-06-07 04:00:00"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testascharacter32#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_ascharacter.testascharacter32#
 #argv <- list(structure(1:4, class = 'roman'));as.character(argv[[1]]);
 [1] "I"   "II"  "III" "IV"
 
@@ -6231,7 +6231,7 @@ a + foo(c) * b
 #foo <- function(x) x*2; f <- function() a+foo(c)*b; as.function(c(alist(a=1+14, b=foo(x),c=), body(f)))(c=3,b=1)
 [1] 21
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction#Output.IgnoreErrorContext#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction#
 #{ .Internal(as.function.default(alist(a+b), "foo")) }
 Error in as.function.default(alist(a + b), "foo") : invalid environment
 
@@ -6970,6 +6970,12 @@ Warning messages:
 1: NAs introduced by coercion
 2: out-of-range values treated as 0 in coercion to raw
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asraw.testAsRaw#Output.IgnoreWarningContext#
+#{ as.raw('10000001') }
+[1] 00
+Warning message:
+out-of-range values treated as 0 in coercion to raw
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_asraw.testAsRaw#Output.IgnoreWarningContext#
 #{ as.raw(-1) }
 [1] 00
@@ -7010,6 +7016,12 @@ out-of-range values treated as 0 in coercion to raw
 #{ as.raw(NULL) }
 raw(0)
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asraw.testAsRaw#Output.IgnoreWarningContext#
+#{ as.raw(c('10000001', '42')) }
+[1] 00 2a
+Warning message:
+out-of-range values treated as 0 in coercion to raw
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_asraw.testAsRaw#Output.IgnoreWarningContext#
 #{ as.raw(c(1+3i, -2-1i, NA)) }
 [1] 01 00 00
@@ -7180,15 +7192,15 @@ Warning messages:
 2: In as.vector("foo", "raw") :
   out-of-range values treated as 0 in coercion to raw
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector#Output.IgnoreErrorContext#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector#
 #{ as.vector(42, NULL) }
 Error in as.vector(x, mode) : invalid 'mode' argument
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector#Output.IgnoreErrorContext#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector#
 #{ as.vector(42, c("character", "character")) }
 Error in as.vector(x, mode) : invalid 'mode' argument
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector#Output.IgnoreErrorContext#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector#
 #{ as.vector(42, character())  }
 Error in as.vector(x, mode) : invalid 'mode' argument
 
@@ -11715,6 +11727,38 @@ head
      [,1]
 [1,] "f"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind#
+#v <- 1:3; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; cbind(v); cbind(v, v)
+     v
+[1,] 1
+[2,] 2
+[3,] 3
+     v v
+[1,] 1 1
+[2,] 2 2
+[3,] 3 3
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind#
+#v <- 1:3; v1<-1:3; attr(v, 'a') <- 'a'; attr(v1, 'a1') <- 'a1'; cbind(v, v1)
+     v v1
+[1,] 1  1
+[2,] 2  2
+[3,] 3  3
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind#
+#v <- 1; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; cbind(v); cbind(v, v)
+     v
+[1,] 1
+     v v
+[1,] 1 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind#
+#v <- 1; attr(v, 'a') <- 'a'; cbind(v); cbind(v, v)
+     v
+[1,] 1
+     v v
+[1,] 1 1
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testCbind#
 #x <- matrix(1:20, 10, 2); dimnames(x) <- list(1:10, c('a','b')); cbind(1, x[,-1,drop=FALSE]);
       b
@@ -11912,6 +11956,332 @@ c 2
   a  c
 1 7 42
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(1L)) }
+$dim
+[1] 1 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(1L, 2L)) }
+$dim
+[1] 1 2
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(NULL, integer(0))) }
+$dim
+[1] 0 2
+
+$dimnames
+$dimnames[[1]]
+NULL
+
+$dimnames[[2]]
+NULL
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(c(1), integer(0))) }
+$dim
+[1] 1 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(c(1L, 2L))) }
+$dim
+[1] 2 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(integer(0))) }
+$dim
+[1] 0 1
+
+$dimnames
+$dimnames[[1]]
+NULL
+
+$dimnames[[2]]
+NULL
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(integer(0), integer(0))) }
+$dim
+[1] 0 2
+
+$dimnames
+$dimnames[[1]]
+NULL
+
+$dimnames[[2]]
+NULL
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(list())) }
+$dim
+[1] 0 1
+
+$dimnames
+$dimnames[[1]]
+NULL
+
+$dimnames[[2]]
+NULL
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(list(1L, 2L))) }
+$dim
+[1] 2 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(matrix())) }
+$dim
+[1] 1 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(matrix(1L, 2L))) }
+$dim
+[1] 2 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(structure(1:4, dim=c(2,2)), 1L)) }
+$dim
+[1] 2 3
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L)) }
+$dim
+[1] 2 3
+
+$dimnames
+$dimnames[[1]]
+[1] "y1" "y2"
+
+$dimnames[[2]]
+[1] "x1" "x2" ""
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L)) }
+$dim
+[1] 2 3
+
+$dimnames
+$dimnames[[1]]
+[1] "y1" "y2"
+
+$dimnames[[2]]
+[1] "x1" "x2" ""
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ attributes(cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0))) }
+$dim
+[1] 2 2
+
+$dimnames
+$dimnames[[1]]
+[1] "y1" "y2"
+
+$dimnames[[2]]
+[1] "x1" "x2"
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ cbind(NULL, integer(0)) }
+     [,1] [,2]
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ cbind(c(1), integer(0)) }
+     [,1]
+[1,]    1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ cbind(integer(0), integer(0)) }
+     [,1] [,2]
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ cbind(structure(1:4, dim=c(2,2)), 1L) }
+     [,1] [,2] [,3]
+[1,]    1    3    1
+[2,]    2    4    1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ cbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L) }
+   x1 x2
+y1  1  3 1
+y2  2  4 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L) }
+   x1 x2
+y1  1  3 1
+y2  2  4 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testDimnames#
+#{ cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0)) }
+   x1 x2
+y1  1  3
+y2  2  4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; cbind.foo <- function(...) 'foo'; cbind(v) }
+     v
+[1,] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; assign('cbind.foo', function(x) {'foo'}, envir=.__S3MethodsTable__.); result <- cbind(v) ; rm('cbind.foo', envir=.__S3MethodsTable__.); result;}
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind(v) }
+     v
+[1,] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#Ignored.WrongCaller#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function() 'foo'; cbind(v) }
+Error in cbind(deparse.level, ...) : unused argument (1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(...) 'foo'; cbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(...) 'foo'; v2 <- 1; class(v2) <- 'foo'; cbind(v2) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(deparse.level, ...) 'foo'; cbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(deparse.level, x) 'foo'; cbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(deparse.level, x1, x2) 'foo'; cbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(x) 'foo'; cbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(x0, deparse.level, x1, x2) 'foo'; cbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(x0, x1, x2) 'foo'; cbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#Ignored.ReferenceError#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- length; cbind(v) }
+
+ *** caught segfault ***
+address 0x7fbc0000007d, cause 'memory not mapped'
+
+Traceback:
+ 1: cbind(deparse.level, ...)
+ 2: cbind(v)
+An irrecoverable exception occurred. R is aborting now ...
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#Output.IgnoreErrorContext#
+#{ v <- 1; class(v) <- 'foo'; cbind.foo <- rawToBits; cbind(v) }
+Error in cbind(deparse.level, ...) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- c('foo1', 'foo2'); cbind.foo1 <- function(...) 'foo1'; cbind(v) }
+[1] "foo1"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- c('foo1', 'foo2'); cbind.foo1 <- function(...) 'foo1'; cbind.foo2 <- function(...) 'foo2'; cbind(v) }
+[1] "foo1"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v <- 1; class(v) <- c('foo1', 'foo2'); cbind.foo2 <- function(...) 'foo2'; cbind(v) }
+[1] "foo2"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v1 <- 1; class(v1) <- 'foo1'; cbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; cbind(v1, v2) }
+[1] "foo1"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v1 <- 1; class(v1) <- 'foo1'; cbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; cbind.foo2 <- function(...) 'foo2'; cbind(v1, v2) }
+     v1 v2
+[1,]  1  2
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testGenericDispatch#
+#{ v1 <- 1; class(v1) <- 'foo1'; v2 <- 2; class(v2) <- 'foo2'; cbind.foo2 <- function(...) 'foo2'; cbind(v1, v2) }
+[1] "foo2"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL))
+NULL
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL, NULL, double(0)))
+structure(numeric(0), .Dim = c(0L, 3L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL, NULL, double(0), character(0)))
+structure(character(0), .Dim = c(0L, 4L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL, NULL, double(0), integer(0)))
+structure(numeric(0), .Dim = c(0L, 4L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL, NULL, double(0), integer(0), character(0)))
+structure(character(0), .Dim = c(0L, 5L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL, NULL, integer(0)))
+structure(integer(0), .Dim = c(0L, 3L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL, NULL, integer(0), double(0)))
+structure(numeric(0), .Dim = c(0L, 4L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(NULL, integer(0)))
+structure(integer(0), .Dim = c(0L, 2L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(c(NULL, NULL), integer(0)))
+structure(integer(0), .Dim = c(0L, 2L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(integer(0)))
+structure(integer(0), .Dim = 0:1, .Dimnames = list(NULL, NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testRetType#
+#dput(cbind(integer(0), NULL, NULL))
+structure(integer(0), .Dim = c(0L, 3L), .Dimnames = list(NULL,
+    NULL))
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_cbind.testcbind1#
 #argv <- list(748L, c(5.08759633523238, 4.0943445622221, 5.66642668811243,     3.43398720448515), c(1L, 1L, 1L, 1L), 1L, c(FALSE, TRUE,     TRUE, TRUE), c(0, 1, 0, 1), c(0, 1, 1, 1), c(0, 1, 0, 1),     c(FALSE, FALSE, TRUE, FALSE), c(FALSE, FALSE, FALSE, TRUE));do.call('cbind', argv)
      [,1]     [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
@@ -16408,6 +16778,18 @@ a[a <- TRUE]
 #{ x<-expression(1); deparse(x) }
 [1] "expression(1)"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testDeparseStructure#
+#{ deparse(structure(.Data=c(1,2))) }
+[1] "c(1, 2)"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testDeparseStructure#
+#{ deparse(structure(.Data=c(1,2), attr1=c(1))) }
+[1] "structure(c(1, 2), attr1 = 1)"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testDeparseStructure#
+#{ deparse(structure(.Data=c(1,2), attr1=c(1), attr2=c(2))) }
+[1] "structure(c(1, 2), attr1 = 1, attr2 = 2)"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testdeparse1#
 #argv <- list(quote(rsp), 60L, FALSE, 69, -1L); .Internal(deparse(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))
 [1] "rsp"
@@ -23832,6 +24214,26 @@ Levels: a.b.c a.b.b.c a.c
 #argv <- list(structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')));isS4(argv[[1]]);
 [1] FALSE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isSingle.testisSingle0#
+#is.single
+function (x)  .Primitive("is.single")
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isSingle.testisSingle1#
+#is.single()
+Error in is.single() : 0 arguments passed to 'is.single' which requires 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isSingle.testisSingle2#
+#is.single(0)
+Error in is.single(0) : type "single" unimplemented in R
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isSingle.testisSingle3#
+#is.single(NULL)
+Error in is.single(NULL) : type "single" unimplemented in R
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_isSingle.testisSingle4#
+#is.single(+)
+Error: unexpected ')' in "is.single(+)"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_isTRUE.testIsTRUE#
 #{ file.path("a", "b", c("d","e","f")) }
 [1] "a/b/d" "a/b/e" "a/b/f"
@@ -28747,10 +29149,12 @@ NULL
 
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testlist43#
-#argv <- list(raster = structure('#000000', .Dim = c(1L, 1L), class = 'raster'), x = structure(0, unit = 'npc', valid.unit = 0L, class = 'unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), width = NULL, height = NULL, just = 'centre', hjust = NULL, vjust = NULL, interpolate = TRUE, name = NULL, gp = structure(list(), class = 'gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]],argv[[12]]);
+#argv <- list(raster = structure('#000000', .Dim = c(1L, 1L), class = 'r_raster'), x = structure(0, unit = 'npc', valid.unit = 0L, class = 'r_unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), width = NULL, height = NULL, just = 'centre', hjust = NULL, vjust = NULL, interpolate = TRUE, name = NULL, gp = structure(list(), class = 'r_gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]],argv[[12]]);
 [[1]]
      [,1]
 [1,] "#000000"
+attr(,"class")
+[1] "r_raster"
 
 [[2]]
 [1] 0
@@ -28759,7 +29163,7 @@ attr(,"unit")
 attr(,"valid.unit")
 [1] 0
 attr(,"class")
-[1] "unit"
+[1] "r_unit"
 
 [[3]]
 [1] 0.5
@@ -28768,7 +29172,7 @@ attr(,"unit")
 attr(,"valid.unit")
 [1] 0
 attr(,"class")
-[1] "unit"
+[1] "r_unit"
 
 [[4]]
 NULL
@@ -28794,7 +29198,7 @@ NULL
 [[11]]
 list()
 attr(,"class")
-[1] "gpar"
+[1] "r_gpar"
 
 [[12]]
 NULL
@@ -29419,7 +29823,7 @@ attr(,"class")attr(,"package")
 
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testlist9#
-#argv <- list(label = '', x = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), just = 'centre', hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = NULL, gp = structure(list(), class = 'gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]]);
+#argv <- list(label = '', x = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), just = 'centre', hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = NULL, gp = structure(list(), class = 'r_gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]]);
 [[1]]
 [1] ""
 
@@ -29430,7 +29834,7 @@ attr(,"unit")
 attr(,"valid.unit")
 [1] 0
 attr(,"class")
-[1] "unit"
+[1] "r_unit"
 
 [[3]]
 [1] 0.5
@@ -29439,7 +29843,7 @@ attr(,"unit")
 attr(,"valid.unit")
 [1] 0
 attr(,"class")
-[1] "unit"
+[1] "r_unit"
 
 [[4]]
 [1] "centre"
@@ -29462,7 +29866,7 @@ NULL
 [[10]]
 list()
 attr(,"class")
-[1] "gpar"
+[1] "r_gpar"
 
 [[11]]
 NULL
@@ -33920,6 +34324,14 @@ NULL
 [1] "some"
 [1] "test"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testBooleanOperators#
+#as.symbol('*') == '*'
+[1] TRUE
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testBooleanOperators#
+#as.symbol('<-') == '<-'
+[1] TRUE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testColon#
 #8.2:NULL
 Error in 8.2:NULL : argument of length 0
@@ -35051,7 +35463,7 @@ x
    0    1    2    3    4    5    6    7    8
 TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testoperators118#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testoperators118#
 #argv <- list(structure(c('white', 'aquamarine3', 'bisque2', 'blueviolet', 'burlywood4', 'chartreuse4', 'coral4', 'cyan3', 'darkgreen', 'darkorange1', 'aliceblue', 'white', 'white', 'white', 'white', 'chocolate', 'cornflowerblue', 'cyan4', 'darkgrey', 'darkorange2', 'antiquewhite', 'white', 'white', 'white', 'white', 'chocolate1', 'cornsilk', 'darkblue', 'darkkhaki', 'darkorange3', 'antiquewhite1', 'white', 'white', 'white', 'white', 'chocolate2', 'cornsilk1', 'darkcyan', 'darkmagenta', 'darkorange4', 'antiquewhite2', 'azure2', 'blanchedalmond', 'brown3', 'cadetblue3', 'chocolate3', 'cornsilk2', 'darkgoldenrod', 'darkolivegreen', 'darkorchid', 'antiquewhite3', 'azure3', 'blue', 'brown4', 'cadetblue4', 'chocolate4', 'cornsilk3', 'darkgoldenrod1', 'darkolivegreen1', 'darkorchid1', 'antiquewhite4', 'azure4', 'blue1', 'burlywood', 'chartreuse', 'coral', 'cornsilk4', 'darkgoldenrod2', 'darkolivegreen2', 'darkorchid2', 'aquamarine', 'beige', 'blue2', 'burlywood1', 'chartreuse1', 'coral1', 'cyan', 'darkgoldenrod3', 'darkolivegreen3', 'darkorchid3', 'aquamarine1', 'bisque', 'blue3', 'burlywood2', 'chartreuse2', 'coral2', 'cyan1', 'darkgoldenrod4', 'darkolivegreen4', 'darkorchid4', 'aquamarine2', 'bisque1', 'blue4', 'burlywood3', 'chartreuse3', 'coral3', 'cyan2', 'darkgray', 'darkorange', 'darkred'), .Dim = c(10L, 10L), class = 'raster'), 'white');`==`(argv[[1]],argv[[2]]);
        [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  [,7]  [,8]  [,9] [,10]
  [1,]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
@@ -39299,6 +39711,10 @@ In addition: Warning message:
 In file(filename, "r", encoding = encoding) :
   cannot open file 'test/r/simple/data/tree2/setx.r': No such file or directory
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_parse.testSrcfile#
+#parse(text='', srcfile=srcfile(system.file('testfile')))
+expression()
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPaste#
 #{ a <- as.raw(200) ; b <- as.raw(255) ; paste(a, b) }
 [1] "c8 ff"
@@ -39323,6 +39739,26 @@ character(0)
 #{ paste(sep="") }
 character(0)
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPasteWithS3AsCharacter#
+#{ as.character.myc <- function(x) '42'; val <- 'hello'; class(val) <- 'myc'; paste(val, 'world') }
+[1] "hello world"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPasteWithS3AsCharacter#
+#{ as.character.myc <- function(x) '42'; val <- 3.14; class(val) <- 'myc'; paste(val, 'world') }
+[1] "42 world"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPasteWithS3AsCharacter#
+#{ as.character.myc <- function(x) 42; val <- 3.14; class(val) <- 'myc'; paste(val, 'world') }
+Error in paste(val, "world") : non-string argument to internal 'paste'
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPasteWithS3AsCharacter#
+#{ as.character.myc <- function(x) NULL; val <- 3.14; class(val) <- 'myc'; paste(val, 'world') }
+Error in paste(val, "world") : non-string argument to internal 'paste'
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testPasteWithS3AsCharacter#
+#{ assign('as.character.myc', function(x) '42', envir=.__S3MethodsTable__.); val <- 3.14; class(val) <- 'myc'; res <- paste(val, 'world'); rm('as.character.myc', envir=.__S3MethodsTable__.); res }
+[1] "42 world"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_paste.testpaste1#
 #argv <- list(list('%%  ~~objects to See Also as', '\\code{\\link{~~fun~~}}, ~~~'), ' ', NULL); .Internal(paste(argv[[1]], argv[[2]], argv[[3]]))
 [1] "%%  ~~objects to See Also as \\code{\\link{~~fun~~}}, ~~~"
@@ -41290,6 +41726,9 @@ $ix
  [1] -Inf -Inf -Inf -Inf -Inf -Inf    0    1    2    3    4    5  Inf  Inf  Inf
 [16]  Inf  Inf
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_quit.testQuitEmptyEnv#
+#{ quit("yes") }
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_quit.testQuitErrorSave#
 #{ quit("xx") }
 Error in quit(save, status, runLast) : unrecognized value of 'save'
@@ -41388,6 +41827,66 @@ NULL
 #argv <- list(structure(integer(0), .Label = character(0), class = 'factor'), TRUE, FALSE); .Internal(radixsort(argv[[1]], argv[[2]], argv[[3]]))
 NULL
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, -Inf, 3.44, Inf, 1.513))
+[1] -Inf  Inf
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, -Inf, 3.44, Inf, 1.513), finite=T)
+[1] 1.513 3.440
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, -Inf, 3.44, Inf, 1.513), na.rm=T)
+[1] -Inf  Inf
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, 2.62, 3.44, NA, NA, 1.513))
+[1] NA NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, 2.62, 3.44, NA, NA, 1.513), finite=T)
+[1] 1.513 3.440
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, 2.62, 3.44, NA, NA, 1.513), na.rm=T)
+[1] 1.513 3.440
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, 2.62, 3.44, NaN, 1.513))
+[1] NaN NaN
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, 2.62, 3.44, NaN, 1.513), finite=T)
+[1] 1.513 3.440
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithDoubles#
+#range(c(1.615, 3.19, 2.62, 3.44, NaN, 1.513), na.rm=T)
+[1] 1.513 3.440
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithIntegers#
+#range(c(2L, 3L, NA, NA, 1L))
+[1] NA NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithIntegers#
+#range(c(2L, 3L, NA, NA, 1L), finite=T)
+[1] 1 3
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithIntegers#
+#range(c(2L, 3L, NA, NA, 1L), na.rm=T)
+[1] 1 3
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithLogical#
+#range(c(T, F, NA, NA, T))
+[1] NA NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithLogical#
+#range(c(T, F, NA, NA, T), finite=T)
+[1] NA NA
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithLogical#
+#range(c(T, F, NA, NA, T), na.rm=T)
+[1] 0 1
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testrange1#
 #argv <- list(c(0.0303542455381287, 0.030376780241572, 0.030376780241572, 0.0317964665585001, 0.0332612222823148, 0.0332612222823148, 0.0332612222823148, 0.0332612222823148, 0.0332612222823148, 0.0332612222823148, 0.0332612222823148, 0.0334189652064179, 0.0352217414818821, 0.0354245538128718, 0.0354245538128718, 0.0376780241572021, 0.0376780241572021, 0.0376780241572021, 0.0376780241572021, 0.0406300703082748, 0.0406300703082748, 0.0406300703082748, 0.0440778799351001, 0.048021453037678, 0.0524607896160087, 0.0524607896160087, 0.0524607896160087, 0.0628267531999279, 0.0693167477915991, 0.0981611681990265, 0.134937804218497, 0.179646655850009, 0.437804218496485));range(argv[[1]][[1]],argv[[1]][[2]], na.rm = FALSE);
 [1] 0.03035425 0.03037678
@@ -41970,6 +42469,255 @@ Error in rawToBits(stdout()) : argument 'x' must be a raw vector
 #argv <- structure(list(x = as.raw(c(115, 116, 114, 105, 110,     103))), .Names = 'x');do.call('rawToChar', argv)
 [1] "string"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(1L)) }
+$dim
+[1] 1 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(1L, 2L)) }
+$dim
+[1] 2 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(NULL, integer(0))) }
+$dim
+[1] 2 0
+
+$dimnames
+$dimnames[[1]]
+NULL
+
+$dimnames[[2]]
+NULL
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(c(1), integer(0))) }
+$dim
+[1] 1 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(c(1L, 2L))) }
+$dim
+[1] 1 2
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(integer(0))) }
+$dim
+[1] 1 0
+
+$dimnames
+$dimnames[[1]]
+NULL
+
+$dimnames[[2]]
+NULL
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(integer(0), integer(0))) }
+$dim
+[1] 2 0
+
+$dimnames
+$dimnames[[1]]
+NULL
+
+$dimnames[[2]]
+NULL
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(structure(1:4, dim=c(2,2)), 1L)) }
+$dim
+[1] 3 2
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L)) }
+$dim
+[1] 3 2
+
+$dimnames
+$dimnames[[1]]
+[1] "y1" "y2" ""
+
+$dimnames[[2]]
+[1] "x1" "x2"
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L)) }
+$dim
+[1] 3 2
+
+$dimnames
+$dimnames[[1]]
+[1] "y1" "y2" ""
+
+$dimnames[[2]]
+[1] "x1" "x2"
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ attributes(rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0))) }
+$dim
+[1] 2 2
+
+$dimnames
+$dimnames[[1]]
+[1] "y1" "y2"
+
+$dimnames[[2]]
+[1] "x1" "x2"
+
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ rbind(NULL, integer(0)) }
+
+[1,]
+[2,]
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ rbind(c(1), integer(0)) }
+     [,1]
+[1,]    1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ rbind(integer(0), integer(0)) }
+
+[1,]
+[2,]
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ rbind(structure(1:4, dim=c(2,2)), 1L) }
+     [,1] [,2]
+[1,]    1    3
+[2,]    2    4
+[3,]    1    1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ rbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L) }
+   x1 x2
+y1  1  3
+y2  2  4
+    1  1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L) }
+   x1 x2
+y1  1  3
+y2  2  4
+    1  1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testDimnames#
+#{ rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0)) }
+   x1 x2
+y1  1  3
+y2  2  4
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; assign('rbind.foo', function(x) {'foo'}, envir=.__S3MethodsTable__.); result <- rbind(v) ; rm('rbind.foo', envir=.__S3MethodsTable__.); result;}
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind(v) }
+  [,1]
+v    1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#Ignored.WrongCaller#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function() 'foo'; rbind(v) }
+Error in rbind(deparse.level, ...) : unused argument (1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(...) 'foo'; rbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(...) 'foo'; v2 <- 1; class(v2) <- 'foo'; rbind(v2) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(deparse.level, ...) 'foo'; rbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(deparse.level, x) 'foo'; rbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(deparse.level, x1, x2) 'foo'; rbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(x) 'foo'; rbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(x0, deparse.level, x1, x2) 'foo'; rbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(x0, x1, x2) 'foo'; rbind(v) }
+[1] "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#Ignored.ReferenceError#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- length; rbind(v) }
+
+ *** caught segfault ***
+address 0x7fb70000007d, cause 'memory not mapped'
+
+Traceback:
+ 1: rbind(deparse.level, ...)
+ 2: rbind(v)
+An irrecoverable exception occurred. R is aborting now ...
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#Output.IgnoreErrorContext#
+#{ v <- 1; class(v) <- 'foo'; rbind.foo <- rawToBits; rbind(v) }
+Error in rbind(deparse.level, ...) : argument 'x' must be a raw vector
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- c('foo1', 'foo2'); rbind.foo1 <- function(...) 'foo1'; rbind(v) }
+[1] "foo1"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- c('foo1', 'foo2'); rbind.foo1 <- function(...) 'foo1'; rbind.foo2 <- function(...) 'foo2'; rbind(v) }
+[1] "foo1"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; class(v) <- c('foo1', 'foo2'); rbind.foo2 <- function(...) 'foo2'; rbind(v) }
+[1] "foo2"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v <- 1; rbind.foo <- function(...) 'foo'; rbind(v) }
+  [,1]
+v    1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v1 <- 1; class(v1) <- 'foo1'; rbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind(v1, v2) }
+[1] "foo1"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v1 <- 1; class(v1) <- 'foo1'; rbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind.foo2 <- function(...) 'foo2'; rbind(v1, v2) }
+   [,1]
+v1    1
+v2    2
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testGenericDispatch#
+#{ v1 <- 1; class(v1) <- 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind.foo2 <- function(...) 'foo2'; rbind(v1, v2) }
+[1] "foo2"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRbind#
 #rbind(55, character(0))
      [,1]
@@ -41990,6 +42738,36 @@ a "55"
      [,1]
 [1,] "f"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRbind#
+#v <- 1:3; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; rbind(v); rbind(v, v)
+  [,1] [,2] [,3]
+v    1    2    3
+  [,1] [,2] [,3]
+v    1    2    3
+v    1    2    3
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRbind#
+#v <- 1:3; v1<-1:3; attr(v, 'a') <- 'a'; attr(v1, 'a1') <- 'a1'; rbind(v, v1)
+   [,1] [,2] [,3]
+v     1    2    3
+v1    1    2    3
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRbind#
+#v <- 1; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; rbind(v); rbind(v, v)
+  [,1]
+v    1
+  [,1]
+v    1
+v    1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRbind#
+#v <- 1; attr(v, 'a') <- 'a'; rbind(v); rbind(v, v)
+  [,1]
+v    1
+  [,1]
+v    1
+v    1
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRbind#
 #{ info <- c("print", "AES", "print.AES") ; ns <- integer(0) ; rbind(info, ns) }
      [,1]    [,2]  [,3]
@@ -42163,6 +42941,60 @@ B 2 4
 a  7
 c 42
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL))
+NULL
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL, NULL, double(0)))
+structure(numeric(0), .Dim = c(3L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL, NULL, double(0), character(0)))
+structure(character(0), .Dim = c(4L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL, NULL, double(0), integer(0)))
+structure(numeric(0), .Dim = c(4L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL, NULL, double(0), integer(0), character(0)))
+structure(character(0), .Dim = c(5L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL, NULL, integer(0)))
+structure(integer(0), .Dim = c(3L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL, NULL, integer(0), double(0)))
+structure(numeric(0), .Dim = c(4L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(NULL, integer(0)))
+structure(integer(0), .Dim = c(2L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(c(NULL, NULL), integer(0)))
+structure(integer(0), .Dim = c(2L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(integer(0)))
+structure(integer(0), .Dim = c(1L, 0L), .Dimnames = list(NULL,
+    NULL))
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testRetType#
+#dput(rbind(integer(0), NULL, NULL))
+structure(integer(0), .Dim = c(3L, 0L), .Dimnames = list(NULL,
+    NULL))
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rbind.testrbind1#
 #argv <- list(structure(c(3, 3, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,     8, 8, 8, 8, 8, 9, 9, 11, 11, 13, 13, 13, 13, 13, 13, 13,     14, 14, 14, 14, 16, 16, 31, 31, 31, 33, 33, 43, 43, 43, 61,     61, 61, 62, 62, 106, 106, 110, 110, 110, 110, 163, 163, 165,     165, 165, 168, 168, 172, 172, 172, 204, 204, 206, 206, 206,     206, 206, 211, 211, 241, 241, 241, 241, 244, 244, 249, 249,     250, 250, 250, 250, 252, 252, 252, 252, 252, 252, 252, 252,     252, 252, 252, 252, 256, 256, 265, 265, 265, 265, 265, 265,     265, 265, 265, 267, 267, 267, 269, 269, 269, 291, 291, 291,     291, 291, 291, 291, 312, 312, 312, 312, 312, 314, 314, 314,     314, 314, 2.484906649788, 6.27476202124194, 3.97029191355212,     3.98898404656427, 4.52178857704904, 0, 2.30258509299405,     4.59511985013459, 1.6094379124341, 2.94443897916644, 1.94591014905531,     2.99573227355399, 4.36944785246702, 1.38629436111989, 2.39789527279837,     3.98898404656427, 2.07944154167984, 5.64897423816121, 5.75574221358691,     2.89037175789616, 3.09104245335832, 4.70953020131233, 4.98360662170834,     1.6094379124341, 1.6094379124341, 4.70048036579242, 1.6094379124341,     4.54329478227, 1.6094379124341, 4.49980967033027, 5.62762111369064,     5.11799381241676, 2.39789527279837, 6.28785856016178, 5.4380793089232,     3.63758615972639, 5.76205138278018, 2.83321334405622, 5.7037824746562,     5.90263333340137, 3.40119738166216, 3.63758615972639, 4.31748811353631,     5.58724865840025, 5.32787616878958, 4.06044301054642, 6.22059017009974,     6.20455776256869, 5.2040066870768, 6.20253551718792, 3.78418963391826,     2.94443897916644, 2.63905732961526, 6.24804287450843, 2.63905732961526,     5.74620319054015, 1.79175946922805, 5.44241771052179, 4.99721227376411,     5.93753620508243, 4.02535169073515, 4.74493212836325, 5.90536184805457,     6.00388706710654, 4.91998092582813, 5.73979291217923, 3.13549421592915,     3.17805383034795, 3.58351893845611, 4.89783979995091, 4.49980967033027,     6.0913098820777, 5.75257263882563, 2.30258509299405, 2.77258872223978,     5.28826703069454, 6.10924758276437, 4.74493212836325, 6.16331480403464,     4.57471097850338, 3.55534806148941, 1.38629436111989, 4.46590811865458,     5.93224518744801, 0.693147180559945, 3.95124371858143, 4.0943445622221,     3.17805383034795, 2.484906649788, 5.15905529921453, 3.80666248977032,     2.484906649788, 3.3322045101752, 1.94591014905531, 2.77258872223978,     4.71849887129509, 6.23244801655052, 2.99573227355399, 3.71357206670431,     3.36729582998647, 5.64897423816121, 3.55534806148941, 0.693147180559945,     3.04452243772342, 4.30406509320417, 2.56494935746154, 3.61091791264422,     4.69134788222914, 5.93753620508243, 4.95582705760126, -0.693147180559945,     3.87120101090789, 6.31896811374643, 6.06145691892802, 1.79175946922805,     2.19722457733622, 2.07944154167984, 2.07944154167984, 1.94591014905531,     4.51085950651685, 5.85507192220243, 4.57471097850338, 0.693147180559945,     1.6094379124341, 4.36944785246702, 5.36129216570943, 4.40671924726425,     4.85981240436167, 3.61091791264422, 3.73766961828337, 1,     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,     0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0,     1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0,     1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1,     0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,     1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,     1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,     0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,     0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,     1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1,     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1,     1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1,     0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0,     1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1,     1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1,     1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0,     1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,     0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0,     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1,     0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,     0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0,     1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1,     0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1,     1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0,     0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0,     0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0,     1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1,     1, 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, 1, 0, 0, 0, 0,     0, 0, 0, 1, 0, 1, 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, 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,     0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,     0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,     1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,     0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,     1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0,     0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1,     0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1,     1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1), .Dim = c(130L, 10L)),     structure(c(316, 316, 316, 5.3890717298165, 2.39789527279837,         5.67332326717149, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0,         0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0), .Dim = c(3L, 10L)));do.call('rbind', argv)
        [,1]       [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
@@ -57323,8 +58155,8 @@ integer(0)
 [41] 26163.27 26367.35 26571.43 26775.51 26979.59 27183.67 27387.76 27591.84
 [49] 27795.92 28000.00
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_seq_along.testWithNonStandardLength#Ignored.Unimplemented#
-#{ assign('length.myclass', function(...) 42, envir=.__S3MethodsTable__.); x <- 1; class(x) <- 'myclass'; seq_along(x); }
+##com.oracle.truffle.r.test.builtins.TestBuiltin_seq_along.testWithNonStandardLength#
+#{ assign('length.myclass', function(...) 42, envir=.__S3MethodsTable__.); x <- 1; class(x) <- 'myclass'; res <- seq_along(x); rm('length.myclass', envir=.__S3MethodsTable__.); res }
  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 [26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
 
@@ -60296,7 +61128,7 @@ character(0)
 #argv <- list('p,L,S = (%2d,%2d,%2d): ', TRUE, FALSE, NA); .Internal(sprintf(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))
 [1] "p,L,S = ( 1, 0,NA): "
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_sprintf.testsprintf8#Ignored.Unknown#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_sprintf.testsprintf8#
 #argv <- list('plot_%02g', 1L); .Internal(sprintf(argv[[1]], argv[[2]]))
 [1] "plot_01"
 
@@ -62243,6 +63075,54 @@ Warning message:
 In `[.data.frame`(x = list(Satellites = c(8L, 0L, 9L, 0L, 4L, 0L,  :
   named arguments other than 'drop' are discouraged
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), NA); a
+Error in substitute(quote(x + 1), NA) : invalid environment specified
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), NULL); a
+quote(x + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), c(c(list(x=1)))); a
+quote(1 + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), c(list(x=1), 'breakme')); a
+quote(1 + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), c(list(x=1, 1))); a
+quote(1 + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), list(1)); a
+quote(x + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), list(c(c(list(x=1))))); a
+quote(x + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), list(list(x=1))); a
+quote(x + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), list(x=1)); a
+quote(1 + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+1), list(y=1)); a
+quote(x + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#a<-substitute(quote(x+y), c(list(x=1), list(y=1))); a
+quote(1 + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#f<-function() {}; substitute(quote(x+1), f)
+Error in substitute(quote(x + 1), f) : invalid environment specified
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
 #f<-function(...) { print(typeof(get('...'))); environment() }; e <- f(c(1,2), b=15, c=44); substitute(foo2({...}), e)
 [1] "..."
@@ -62292,6 +63172,47 @@ foo@bar
 #f<-function(x,name) substitute(x@name<-2); f(foo, bar)
 foo@bar <- 2
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(1, 1)
+Error in substitute(1, 1) : invalid environment specified
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(1, 1, 1)
+Error in substitute(1, 1, 1) : unused argument (1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(1, NA)
+Error in substitute(1, NA) : invalid environment specified
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(1, NULL)
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(1, c(list(1)))
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(1, list(c(list(1))))
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(1, list(list(1)))
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(expr=1, env=1)
+Error in substitute(expr = 1, env = 1) : invalid environment specified
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(quote(x+1), environment())
+quote(x + 1)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
+#substitute(quote(x+1), setClass('a'))
+Error in substitute(quote(x + 1), setClass("a")) :
+  invalid environment specified
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_substitute.testSubstitute#
 #{ delayedAssign("expr", a * b) ; substitute(expr) }
 expr
@@ -65526,7 +66447,7 @@ $a
 
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_unclass.testunclass27#
-#argv <- list(list(structure(list(label = 'FALSE', x = structure(0, unit = 'npc', valid.unit = 0L, class = 'unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), just = c('left', 'centre'), hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = 'GRID.text.106', gp = structure(list(), class = 'gpar'), vp = NULL), .Names = c('label', 'x', 'y', 'just', 'hjust', 'vjust', 'rot', 'check.overlap', 'name', 'gp', 'vp'), class = c('text', 'grob', 'gDesc'))));unclass(argv[[1]]);
+#argv <- list(list(structure(list(label = 'FALSE', x = structure(0, unit = 'npc', valid.unit = 0L, class = 'r_unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), just = c('left', 'centre'), hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = 'GRID.text.106', gp = structure(list(), class = 'r_gpar'), vp = NULL), .Names = c('label', 'x', 'y', 'just', 'hjust', 'vjust', 'rot', 'check.overlap', 'name', 'gp', 'vp'), class = c('r_text', 'r_grob', 'r_gDesc'))));unclass(argv[[1]]);
 [[1]]
 $label
 [1] "FALSE"
@@ -65538,7 +66459,7 @@ attr(,"unit")
 attr(,"valid.unit")
 [1] 0
 attr(,"class")
-[1] "unit"
+[1] "r_unit"
 
 $y
 [1] 0.5
@@ -65547,7 +66468,7 @@ attr(,"unit")
 attr(,"valid.unit")
 [1] 0
 attr(,"class")
-[1] "unit"
+[1] "r_unit"
 
 $just
 [1] "left"   "centre"
@@ -65570,13 +66491,13 @@ $name
 $gp
 list()
 attr(,"class")
-[1] "gpar"
+[1] "r_gpar"
 
 $vp
 NULL
 
 attr(,"class")
-[1] "text"  "grob"  "gDesc"
+[1] "r_text"  "r_grob"  "r_gDesc"
 
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_unclass.testunclass28#
@@ -71500,6 +72421,20 @@ $v
 [1] 8
 
 
+##com.oracle.truffle.r.test.functions.TestFunctions.testMatching#
+#{ foo <- function(xa, ...) list(xa=xa, ...); foo(x=4,xa=5); }
+$xa
+[1] 5
+
+$x
+[1] 4
+
+
+##com.oracle.truffle.r.test.functions.TestFunctions.testMatching#
+#{ foo <- function(xaaa, ...) list(xaa=xaaa, ...); foo(xa=4,xaa=5); }
+Error in foo(xa = 4, xaa = 5) :
+  formal argument "xaaa" matched by multiple actual arguments
+
 ##com.oracle.truffle.r.test.functions.TestFunctions.testMatching#
 #{ x<-function(foo,bar){foo*bar} ; x(f=10,2) }
 [1] 20
@@ -72087,11 +73022,11 @@ attr(,".Environment")
 <environment: R_GlobalEnv>
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
-#{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x+x; }
+#{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; res <- x+x; rm('Ops.myclass', envir=.__S3MethodsTable__.); res; }
 [1] 42
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
-#{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x[[99]]; }
+#{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; res <- x[[99]]; rm('[[.myclass', envir=.__S3MethodsTable__.); res; }
 [1] 42
 
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.testMathGroupDispatch#
@@ -72243,6 +73178,30 @@ f first 1
 #{f<-function(x){UseMethod("f")};f.logical<-function(x){print("logical")};f(TRUE)}
 [1] "logical"
 
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.runRSourceTests#
+#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers0.R") }
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.runRSourceTests#Ignored.Unknown#
+#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers1.R") }
+[1] "enter fun1 first"
+[1] "enter handle_cond1 cond1: signalfirst\n"
+[1] "after cond1 restart"
+[1] "enter handle_cond0 cond0: signalfirst\n"
+[1] "continue"
+[1] "exit fun1 first"
+[1] "enter fun1 second"
+[1] "enter handle_cond1 cond1: signalsecond\n"
+[1] "after cond1 restart"
+[1] "enter handle_cond0 cond0: signalsecond\n"
+[1] "continue"
+[1] "exit fun1 second"
+NULL
+[1] "exit fun0"
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testTryCatch#
+#myCondition <- function(message, call=NULL)<<<NEWLINE>>> structure(list(message=message, call=call),<<<NEWLINE>>> class=c("myCondition", "condition"))<<<NEWLINE>>>tryCatch(signalCondition(myCondition("foo")),<<<NEWLINE>>> myCondition=function(cond) {cat("<my>");123L})
+<my>[1] 123
+
 ##com.oracle.truffle.r.test.library.base.TestConditionHandling.testTryCatch#
 #{ e <- simpleError("test error"); f <- function() { tryCatch(1, finally = print("Hello")); stop(e)}; f() }
 [1] "Hello"
@@ -72281,6 +73240,63 @@ Error in f() : fred
 Error in tryCatchList(expr, classes, parentenv, handlers) : fred
 [1] "Hello"
 
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testTryCatch#
+#{ tryCatch(stop("xyz"), error=function(e) { cat("<error>");123L }, finally=function() { cat("<finally>")}) }
+<error>[1] 123
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithCallingHandlers#
+#withCallingHandlers({message("foo");123L},<<<NEWLINE>>> message=function(e) {<<<NEWLINE>>> cat("<msg>")<<<NEWLINE>>> invokeRestart("muffleMessage")<<<NEWLINE>>> })
+<msg>[1] 123
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithCallingHandlers#
+#withCallingHandlers({message("foo");123L},<<<NEWLINE>>> message=function(e) {cat("<msg>")})
+<msg>foo
+[1] 123
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithCallingHandlers#
+#withCallingHandlers({message("foo");packageStartupMessage("bar");123L},<<<NEWLINE>>> packageStartupMessage=function(e) {<<<NEWLINE>>> cat("<msg>")<<<NEWLINE>>> invokeRestart("muffleMessage")<<<NEWLINE>>> })
+foo
+<msg>[1] 123
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithCallingHandlers#Ignored.ImplementationError#
+#withCallingHandlers({warning("foo");123L},<<<NEWLINE>>> warning=function(e) {<<<NEWLINE>>> cat("<warn>")<<<NEWLINE>>> invokeRestart("muffleWarning")<<<NEWLINE>>> })
+<warn>[1] 123
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithCallingHandlers#Output.IgnoreWarningContext#
+#withCallingHandlers({warning("foo");123L},<<<NEWLINE>>> warning=function(e) {cat("<warn>")})
+<warn>[1] 123
+Warning message:
+In withCallingHandlers({ : foo
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithRestarts#
+#withRestarts(computeRestarts(),<<<NEWLINE>>> foo=function(a,b) c(a,b))
+[[1]]
+<restart: foo >
+
+[[2]]
+<restart: abort >
+
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithRestarts#
+#withRestarts(findRestart("foo"),<<<NEWLINE>>> foo=function(a,b) c(a,b))
+<restart: foo >
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithRestarts#
+#withRestarts(findRestart("noSuchRestart"),<<<NEWLINE>>> foo=function(a,b) c(a,b))
+NULL
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithRestarts#
+#withRestarts({cat("<start>");invokeRestart("foo", 123L, 456L);789L},<<<NEWLINE>>> foo=function(a,b) c(a,b))
+<start>[1] 123 456
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithRestarts#
+#withRestarts({cat("<start>");invokeRestart("foo", 123L, 456L);789L},<<<NEWLINE>>> foo=function(a,b) {cat("<first>");invokeRestart("foo", a+1, b+1)},<<<NEWLINE>>> foo=function(a,b) {cat("<second>");c(a,b)})
+<start><first><second>[1] 124 457
+
+##com.oracle.truffle.r.test.library.base.TestConditionHandling.testWithRestarts#
+#withRestarts({cat("<start>");invokeRestart("foo", 123L, 456L);789L},<<<NEWLINE>>> foo=list(description="my handler", handler=function(a,b) c(a,b)))
+<start>[1] 123 456
+
 ##com.oracle.truffle.r.test.library.base.TestConnections.testFileWriteReadBin#
 #{ readBin(file("tmptest/com.oracle.truffle.r.test.library.base.conn/wb1", "rb"), 3) }
 numeric(0)
@@ -79632,6 +80648,31 @@ $z
 [1]  7 43
 
 
+##com.oracle.truffle.r.test.library.base.TestSimpleLists.testNullListAssignment#
+#a<- NULL; a <- `$<-`(a, "a", 1); dput(a)
+structure(list(a = 1), .Names = "a")
+
+##com.oracle.truffle.r.test.library.base.TestSimpleLists.testNullListAssignment#
+#a<- NULL; a <- `$<-`(a, 1, 1); dput(a)
+Error: invalid subscript type 'double'
+
+##com.oracle.truffle.r.test.library.base.TestSimpleLists.testNullListAssignment#
+#a<- NULL; a <- `[[<-`(a, "a", 1); dput(a)
+structure(1, .Names = "a")
+
+##com.oracle.truffle.r.test.library.base.TestSimpleLists.testNullListAssignment#
+#a<- NULL; a <- `[[<-`(a, 1, 1); dput(a)
+1
+
+##com.oracle.truffle.r.test.library.base.TestSimpleLists.testNullListAssignment#
+#a<-NULL; a$b<-42L; dput(a)
+structure(list(b = 42L), .Names = "b")
+
+##com.oracle.truffle.r.test.library.base.TestSimpleLists.testNullListAssignment#
+#a<-NULL; a$b<-print; dput(a)
+structure(list(b = function (x, ...)
+UseMethod("print")), .Names = "b")
+
 ##com.oracle.truffle.r.test.library.base.TestSimpleLoop.testDynamic#
 #{ l <- quote({x <- 0 ; for(i in 1:10) { x <- x + i } ; x}) ; f <- function() { eval(l) } ; x <<- 10 ; f() }
 [1] 55
@@ -124458,6 +125499,184 @@ attr(,"is.truffle.object")
 #if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 } }
 [1] TRUE
 
+##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits#
+#{ library(grid); 3 * (unit(1, 'mm')); }
+[1] 3*1mm
+
+##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits#
+#{ library(grid); grid:::unit.list(3 * unit(1, 'mm')); }
+[1] 3*1mm
+
+##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits#
+#{ library(grid); unit.c(unit(1,'mm'), 42*unit(1,'mm')); }
+[1] 1mm    42*1mm
+
+##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits#
+#{ library(grid); unit.c(unit(1,'mm'), unit(1,'mm')) }
+[1] 1mm 1mm
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), NA); a
+Error in substituteDirect(quote(x + 1), NA) :
+  invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), NULL); a
+Error in substituteDirect(quote(x + 1), NULL) :
+  invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), c(c(list(x=1)))); a
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), c(list(x=1), 'breakme')); a
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), c(list(x=1, 1))); a
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), list(1)); a
+x + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), list(c(c(list(x=1))))); a
+x + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), list(list(x=1))); a
+x + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), list(x=1)); a
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+1), list(y=1)); a
+x + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#a<-substituteDirect(quote(x+y), c(list(x=1), list(y=1))); a
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#f<-function() {}; substituteDirect(quote(x+1), frame=f)
+Error in substituteDirect(quote(x + 1), frame = f) :
+  invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(1, 1)
+Error in substituteDirect(1, 1) : invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(1, 1, 1)
+Error in substituteDirect(1, 1, 1) : invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(1, frame=NA)
+Error in substituteDirect(1, frame = NA) : invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(1, frame=NULL)
+Error in substituteDirect(1, frame = NULL) :
+  invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(NA, list(x=1))
+[1] NA
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(NULL, list(x=1))
+NULL
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(environment(), list(x=1))
+<environment: R_GlobalEnv>
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(object=1, frame=1)
+Error in substituteDirect(object = 1, frame = 1) :
+  invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(object=1, frame=1, cleanFunction=1)
+Error in substituteDirect(object = 1, frame = 1, cleanFunction = 1) :
+  invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(object=1, frame=c(list(1)))
+[1] 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(object=1, frame=list(c(list(1))))
+[1] 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(object=1, frame=list(list(1)))
+[1] 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), frame=environment())
+x + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), frame=setClass('a'))
+Error in substituteDirect(quote(x + 1), frame = setClass("a")) :
+  invalid list for substitution
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction='a')
+Error in cleanFunction && is.function(value) :
+  invalid 'x' type in 'x && y'
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=NA)
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=NULL)
+Error in cleanFunction && is.function(value) :
+  invalid 'x' type in 'x && y'
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=TRUE)
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=c('1'))
+Error in cleanFunction && is.function(value) :
+  invalid 'x' type in 'x && y'
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=c(1))
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=c(TRUE, 'breakme'))
+Error in cleanFunction && is.function(value) :
+  invalid 'x' type in 'x && y'
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=c(TRUE, FALSE))
+1 + 1
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=c(c(TRUE, 'breakme')))
+Error in cleanFunction && is.function(value) :
+  invalid 'x' type in 'x && y'
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=environment())
+Error in cleanFunction && is.function(value) :
+  invalid 'x' type in 'x && y'
+
+##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests#
+#substituteDirect(quote(x+1), list(x=1), cleanFunction=list(c(TRUE), 'breakme'))
+Error in cleanFunction && is.function(value) :
+  invalid 'x' type in 'x && y'
+
 ##com.oracle.truffle.r.test.library.stats.TestDistributions.testDensityFunctions#Output.MayIgnoreWarningContext#
 #dbeta(0, -1,  0.5)
 [1] NaN
@@ -131731,6 +132950,20 @@ list(cyl, hp, mpg, disp, drat, wt, qsec, vs, am, gear, carb)
 9  8  9
 10 9 10
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrame#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.frame(terms.formula(~k+y+z)) }
+    k y  z
+1   2 0  1
+2   3 1  2
+3   4 2  3
+4   5 3  4
+5   6 4  5
+6   7 5  6
+7   8 6  7
+8   9 7  8
+9  10 8  9
+10 11 9 10
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrame#
 #{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.frame(terms.formula(u~z*k+w*m)) }
     u z k  w  m
@@ -131941,6 +133174,20 @@ list(cyl, hp, mpg, disp, drat, wt, qsec, vs, am, gear, carb)
 9  8 c
 10 9 c
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrame#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.frame(terms.formula(~k+y+z)) }
+   k y z
+1  m 0 a
+2  f 1 b
+3  m 2 c
+4  f 3 a
+5  m 4 b
+6  f 5 c
+7  m 6 a
+8  f 7 b
+9  m 8 c
+10 f 9 c
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
 #{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.matrix(model.frame(terms.formula(u~z*k+w*m))) }
    (Intercept)  z  k  w  m z:k w:m
@@ -132182,255 +133429,271 @@ attr(,"assign")
 [1] 0 1
 
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(u~z*k+w*m))) }
-   (Intercept) zb zc km  w  m zb:km zc:km w:m
-1            1  0  0  1  3  4     0     0  12
-2            1  1  0  0  4  5     0     0  20
-3            1  0  1  1  5  6     0     1  30
-4            1  0  0  0  6  7     0     0  42
-5            1  1  0  1  7  8     1     0  56
-6            1  0  1  0  8  9     0     0  72
-7            1  0  0  1  9 10     0     0  90
-8            1  1  0  0 10 11     0     0 110
-9            1  0  1  1 11 12     0     1 132
-10           1  0  1  0 12 13     0     0 156
-attr(,"assign")
-[1] 0 1 1 2 3 4 5 5 6
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-attr(,"contrasts")$k
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~(1 + w/k)))) }
-   (Intercept)  w w:km
-1            1  3    3
-2            1  4    0
-3            1  5    5
-4            1  6    0
-5            1  7    7
-6            1  8    0
-7            1  9    9
-8            1 10    0
-9            1 11   11
-10           1 12    0
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.matrix(model.frame(terms.formula(~k+y+z))) }
+   (Intercept)  k y  z
+1            1  2 0  1
+2            1  3 1  2
+3            1  4 2  3
+4            1  5 3  4
+5            1  6 4  5
+6            1  7 5  6
+7            1  8 6  7
+8            1  9 7  8
+9            1 10 8  9
+10           1 11 9 10
 attr(,"assign")
-[1] 0 1 2
-attr(,"contrasts")
-attr(,"contrasts")$k
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~(z+k)*(w+u)))) }
-   (Intercept) zb zc km  w  u zb:w zc:w zb:u zc:u km:w km:u
-1            1  0  0  1  3  5    0    0    0    0    3    5
-2            1  1  0  0  4  6    4    0    6    0    0    0
-3            1  0  1  1  5  7    0    5    0    7    5    7
-4            1  0  0  0  6  8    0    0    0    0    0    0
-5            1  1  0  1  7  9    7    0    9    0    7    9
-6            1  0  1  0  8 10    0    8    0   10    0    0
-7            1  0  0  1  9 11    0    0    0    0    9   11
-8            1  1  0  0 10 12   10    0   12    0    0    0
-9            1  0  1  1 11 13    0   11    0   13   11   13
-10           1  0  1  0 12 14    0   12    0   14    0    0
-attr(,"assign")
- [1] 0 1 1 2 3 4 5 5 6 6 7 8
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-attr(,"contrasts")$k
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~(z+k)^2))) }
-   (Intercept) zb zc km zb:km zc:km
-1            1  0  0  1     0     0
-2            1  1  0  0     0     0
-3            1  0  1  1     0     1
-4            1  0  0  0     0     0
-5            1  1  0  1     1     0
-6            1  0  1  0     0     0
-7            1  0  0  1     0     0
-8            1  1  0  0     0     0
-9            1  0  1  1     0     1
-10           1  0  1  0     0     0
-attr(,"assign")
-[1] 0 1 1 2 3 3
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-attr(,"contrasts")$k
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~-1+z))) }
-   za zb zc
-1   1  0  0
-2   0  1  0
-3   0  0  1
-4   1  0  0
-5   0  1  0
-6   0  0  1
-7   1  0  0
-8   0  1  0
-9   0  0  1
-10  0  0  1
-attr(,"assign")
-[1] 1 1 1
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~0+z))) }
-   za zb zc
-1   1  0  0
-2   0  1  0
-3   0  0  1
-4   1  0  0
-5   0  1  0
-6   0  0  1
-7   1  0  0
-8   0  1  0
-9   0  0  1
-10  0  0  1
-attr(,"assign")
-[1] 1 1 1
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~1+z))) }
-   (Intercept) zb zc
-1            1  0  0
-2            1  1  0
-3            1  0  1
-4            1  0  0
-5            1  1  0
-6            1  0  1
-7            1  0  0
-8            1  1  0
-9            1  0  1
-10           1  0  1
-attr(,"assign")
-[1] 0 1 1
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~w%in%v))) }
-   (Intercept) w:v
-1            1  18
-2            1  28
-3            1  40
-4            1  54
-5            1  70
-6            1  88
-7            1 108
-8            1 130
-9            1 154
-10           1 180
-attr(,"assign")
-[1] 0 1
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~w/k))) }
-   (Intercept)  w w:km
-1            1  3    3
-2            1  4    0
-3            1  5    5
-4            1  6    0
-5            1  7    7
-6            1  8    0
-7            1  9    9
-8            1 10    0
-9            1 11   11
-10           1 12    0
-attr(,"assign")
-[1] 0 1 2
-attr(,"contrasts")
-attr(,"contrasts")$k
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z))) }
-   (Intercept) zb zc
-1            1  0  0
-2            1  1  0
-3            1  0  1
-4            1  0  0
-5            1  1  0
-6            1  0  1
-7            1  0  0
-8            1  1  0
-9            1  0  1
-10           1  0  1
-attr(,"assign")
-[1] 0 1 1
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z*((m+w)^3)))) }
-   (Intercept) zb zc  m  w m:w zb:m zc:m zb:w zc:w zb:m:w zc:m:w
-1            1  0  0  4  3  12    0    0    0    0      0      0
-2            1  1  0  5  4  20    5    0    4    0     20      0
-3            1  0  1  6  5  30    0    6    0    5      0     30
-4            1  0  0  7  6  42    0    0    0    0      0      0
-5            1  1  0  8  7  56    8    0    7    0     56      0
-6            1  0  1  9  8  72    0    9    0    8      0     72
-7            1  0  0 10  9  90    0    0    0    0      0      0
-8            1  1  0 11 10 110   11    0   10    0    110      0
-9            1  0  1 12 11 132    0   12    0   11      0    132
-10           1  0  1 13 12 156    0   13    0   12      0    156
-attr(,"assign")
- [1] 0 1 1 2 3 4 5 5 6 6 7 7
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-
-##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z*k))) }
-   (Intercept) zb zc km zb:km zc:km
-1            1  0  0  1     0     0
-2            1  1  0  0     0     0
-3            1  0  1  1     0     1
-4            1  0  0  0     0     0
-5            1  1  0  1     1     0
-6            1  0  1  0     0     0
-7            1  0  0  1     0     0
-8            1  1  0  0     0     0
-9            1  0  1  1     0     1
-10           1  0  1  0     0     0
-attr(,"assign")
-[1] 0 1 1 2 3 3
-attr(,"contrasts")
-attr(,"contrasts")$z
-[1] "contr.treatment"
-
-attr(,"contrasts")$k
-[1] "contr.treatment"
-
+[1] 0 1 2 3
 
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
-#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z*k+w*m))) }
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(u~z*k+w*m))) }
+   (Intercept) zb zc km  w  m zb:km zc:km w:m
+1            1  0  0  1  3  4     0     0  12
+2            1  1  0  0  4  5     0     0  20
+3            1  0  1  1  5  6     0     1  30
+4            1  0  0  0  6  7     0     0  42
+5            1  1  0  1  7  8     1     0  56
+6            1  0  1  0  8  9     0     0  72
+7            1  0  0  1  9 10     0     0  90
+8            1  1  0  0 10 11     0     0 110
+9            1  0  1  1 11 12     0     1 132
+10           1  0  1  0 12 13     0     0 156
+attr(,"assign")
+[1] 0 1 1 2 3 4 5 5 6
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+attr(,"contrasts")$k
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~(1 + w/k)))) }
+   (Intercept)  w w:km
+1            1  3    3
+2            1  4    0
+3            1  5    5
+4            1  6    0
+5            1  7    7
+6            1  8    0
+7            1  9    9
+8            1 10    0
+9            1 11   11
+10           1 12    0
+attr(,"assign")
+[1] 0 1 2
+attr(,"contrasts")
+attr(,"contrasts")$k
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~(z+k)*(w+u)))) }
+   (Intercept) zb zc km  w  u zb:w zc:w zb:u zc:u km:w km:u
+1            1  0  0  1  3  5    0    0    0    0    3    5
+2            1  1  0  0  4  6    4    0    6    0    0    0
+3            1  0  1  1  5  7    0    5    0    7    5    7
+4            1  0  0  0  6  8    0    0    0    0    0    0
+5            1  1  0  1  7  9    7    0    9    0    7    9
+6            1  0  1  0  8 10    0    8    0   10    0    0
+7            1  0  0  1  9 11    0    0    0    0    9   11
+8            1  1  0  0 10 12   10    0   12    0    0    0
+9            1  0  1  1 11 13    0   11    0   13   11   13
+10           1  0  1  0 12 14    0   12    0   14    0    0
+attr(,"assign")
+ [1] 0 1 1 2 3 4 5 5 6 6 7 8
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+attr(,"contrasts")$k
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~(z+k)^2))) }
+   (Intercept) zb zc km zb:km zc:km
+1            1  0  0  1     0     0
+2            1  1  0  0     0     0
+3            1  0  1  1     0     1
+4            1  0  0  0     0     0
+5            1  1  0  1     1     0
+6            1  0  1  0     0     0
+7            1  0  0  1     0     0
+8            1  1  0  0     0     0
+9            1  0  1  1     0     1
+10           1  0  1  0     0     0
+attr(,"assign")
+[1] 0 1 1 2 3 3
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+attr(,"contrasts")$k
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~-1+z))) }
+   za zb zc
+1   1  0  0
+2   0  1  0
+3   0  0  1
+4   1  0  0
+5   0  1  0
+6   0  0  1
+7   1  0  0
+8   0  1  0
+9   0  0  1
+10  0  0  1
+attr(,"assign")
+[1] 1 1 1
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~0+z))) }
+   za zb zc
+1   1  0  0
+2   0  1  0
+3   0  0  1
+4   1  0  0
+5   0  1  0
+6   0  0  1
+7   1  0  0
+8   0  1  0
+9   0  0  1
+10  0  0  1
+attr(,"assign")
+[1] 1 1 1
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~1+z))) }
+   (Intercept) zb zc
+1            1  0  0
+2            1  1  0
+3            1  0  1
+4            1  0  0
+5            1  1  0
+6            1  0  1
+7            1  0  0
+8            1  1  0
+9            1  0  1
+10           1  0  1
+attr(,"assign")
+[1] 0 1 1
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~w%in%v))) }
+   (Intercept) w:v
+1            1  18
+2            1  28
+3            1  40
+4            1  54
+5            1  70
+6            1  88
+7            1 108
+8            1 130
+9            1 154
+10           1 180
+attr(,"assign")
+[1] 0 1
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~w/k))) }
+   (Intercept)  w w:km
+1            1  3    3
+2            1  4    0
+3            1  5    5
+4            1  6    0
+5            1  7    7
+6            1  8    0
+7            1  9    9
+8            1 10    0
+9            1 11   11
+10           1 12    0
+attr(,"assign")
+[1] 0 1 2
+attr(,"contrasts")
+attr(,"contrasts")$k
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z))) }
+   (Intercept) zb zc
+1            1  0  0
+2            1  1  0
+3            1  0  1
+4            1  0  0
+5            1  1  0
+6            1  0  1
+7            1  0  0
+8            1  1  0
+9            1  0  1
+10           1  0  1
+attr(,"assign")
+[1] 0 1 1
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z*((m+w)^3)))) }
+   (Intercept) zb zc  m  w m:w zb:m zc:m zb:w zc:w zb:m:w zc:m:w
+1            1  0  0  4  3  12    0    0    0    0      0      0
+2            1  1  0  5  4  20    5    0    4    0     20      0
+3            1  0  1  6  5  30    0    6    0    5      0     30
+4            1  0  0  7  6  42    0    0    0    0      0      0
+5            1  1  0  8  7  56    8    0    7    0     56      0
+6            1  0  1  9  8  72    0    9    0    8      0     72
+7            1  0  0 10  9  90    0    0    0    0      0      0
+8            1  1  0 11 10 110   11    0   10    0    110      0
+9            1  0  1 12 11 132    0   12    0   11      0    132
+10           1  0  1 13 12 156    0   13    0   12      0    156
+attr(,"assign")
+ [1] 0 1 1 2 3 4 5 5 6 6 7 7
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z*k))) }
+   (Intercept) zb zc km zb:km zc:km
+1            1  0  0  1     0     0
+2            1  1  0  0     0     0
+3            1  0  1  1     0     1
+4            1  0  0  0     0     0
+5            1  1  0  1     1     0
+6            1  0  1  0     0     0
+7            1  0  0  1     0     0
+8            1  1  0  0     0     0
+9            1  0  1  1     0     1
+10           1  0  1  0     0     0
+attr(,"assign")
+[1] 0 1 1 2 3 3
+attr(,"contrasts")
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+attr(,"contrasts")$k
+[1] "contr.treatment"
+
+
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(y~z*k+w*m))) }
    (Intercept) zb zc km  w  m zb:km zc:km w:m
 1            1  0  0  1  3  4     0     0  12
 2            1  1  0  0  4  5     0     0  20
@@ -132495,6 +133758,29 @@ attr(,"contrasts")$z
 [1] "contr.treatment"
 
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix#
+#{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;k <- factor(rep(c('m', 'f'), 5));z <- factor(c(rep(c('a', 'b', 'c'), 3), 'c')); ; model.matrix(model.frame(terms.formula(~k+y+z))) }
+   (Intercept) km y zb zc
+1            1  1 0  0  0
+2            1  0 1  1  0
+3            1  1 2  0  1
+4            1  0 3  0  0
+5            1  1 4  1  0
+6            1  0 5  0  1
+7            1  1 6  0  0
+8            1  0 7  1  0
+9            1  1 8  0  1
+10           1  0 9  0  1
+attr(,"assign")
+[1] 0 1 2 3 3
+attr(,"contrasts")
+attr(,"contrasts")$k
+[1] "contr.treatment"
+
+attr(,"contrasts")$z
+[1] "contr.treatment"
+
+
 ##com.oracle.truffle.r.test.library.stats.TestFormulae.testSpecialsTermsform#
 #f <- terms.formula(y~myfun(z)+x, c('myfun')); attrs <- attributes(f); envIdx <- which(names(attrs)=='.Environment'); print(attrs[envIdx]); attrs[sort(names(attrs[-envIdx]))]
 $.Environment
@@ -132991,6 +134277,36 @@ $variables
 list(y, z)
 
 
+##com.oracle.truffle.r.test.library.stats.TestFormulae.testTermsform#
+#f <- terms.formula(~k+y+z); attrs <- attributes(f); envIdx <- which(names(attrs)=='.Environment'); print(attrs[envIdx]); attrs[sort(names(attrs[-envIdx]))]
+$.Environment
+<environment: R_GlobalEnv>
+
+$class
+[1] "terms"   "formula"
+
+$factors
+  k y z
+k 1 0 0
+y 0 1 0
+z 0 0 1
+
+$intercept
+[1] 1
+
+$order
+[1] 1 1 1
+
+$response
+[1] 0
+
+$term.labels
+[1] "k" "y" "z"
+
+$variables
+list(k, y, z)
+
+
 ##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions1#Output.IgnoreWhitespace#
 #set.seed(10); rsignrank(12, c(NA, NaN, 1/0, -1/0, -1, 1, 0.3, -0.6, 0.0653, 0.000123, 32e-80, 10))
  [1] NA NA  0 NA NA  1  0 NA  0  0  0 21
@@ -133534,6 +134850,651 @@ 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.TestSplineFunctions.basicSplineCoef#Ignored.WrongCaller#
+#.Call(stats:::C_SplineCoef, 'abc', c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+Warning message:
+NAs introduced by coercion
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, -1, c(1:5), c(1:5))
+$method
+[1] -1
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 0, c(1:5), c(1:5))
+$method
+[1] 0
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, NA, NA)
+$method
+[1] 1
+
+$n
+[1] 1
+
+$x
+[1] NA
+
+$y
+[1] NA
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, NA, c(1:5))
+Error: inputs of different lengths
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, NULL, NULL)
+$method
+[1] 1
+
+$n
+[1] 0
+
+$x
+numeric(0)
+
+$y
+numeric(0)
+
+$b
+numeric(0)
+
+$c
+numeric(0)
+
+$d
+numeric(0)
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, NULL, c(1:5))
+Error: inputs of different lengths
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, c(1), c(1))
+$method
+[1] 1
+
+$n
+[1] 1
+
+$x
+[1] 1
+
+$y
+[1] 1
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, c(1), list(1))
+$method
+[1] 1
+
+$n
+[1] 1
+
+$x
+[1] 1
+
+$y
+[1] 1
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, c(1:5), NA)
+Error: inputs of different lengths
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, c(1:5), NULL)
+Error: inputs of different lengths
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, c(1:5), c(1:5))
+$method
+[1] 1
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, c(1:6), c(1:5, 1))
+$method
+[1] 1
+
+$n
+[1] 6
+
+$x
+[1] 1 2 3 4 5 6
+
+$y
+[1] 1 2 3 4 5 1
+
+$b
+[1] -2.1818182  1.9090909  0.5454545  1.9090909 -2.1818182 -2.1818182
+
+$c
+[1]  5.454545e+00 -1.363636e+00 -2.154731e-17  1.363636e+00 -5.454545e+00
+[6]  5.454545e+00
+
+$d
+[1] -2.2727273  0.4545455  0.4545455 -2.2727273  3.6363636 -2.2727273
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 1, list(1), c(1))
+$method
+[1] 1
+
+$n
+[1] 1
+
+$x
+[1] 1
+
+$y
+[1] 1
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 111, c(1:5), c(1:5))
+$method
+[1] 111
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 2, c(1), c(1))
+$method
+[1] 2
+
+$n
+[1] 1
+
+$x
+[1] 1
+
+$y
+[1] 1
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 2, c(1:5), c(1:5))
+$method
+[1] 2
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 1 1 1 1 1
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 3, c(1:5), c(1:5))
+$method
+[1] 3
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 1 1 1 1 1
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, 4, c(1:5), c(1:5))
+$method
+[1] 4
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, NA, c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, NULL, c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#Ignored.WrongCaller#
+#.Call(stats:::C_SplineCoef, c('a'), c(1), c(1))
+$method
+[1] NA
+
+$n
+[1] 1
+
+$x
+[1] 1
+
+$y
+[1] 1
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+Warning message:
+NAs introduced by coercion
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, c(), c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, c(1), c(1:5), c(1:5))
+$method
+[1] 1
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, c(1, 2, 3), c(1), c(1))
+$method
+[1] 1
+
+$n
+[1] 1
+
+$x
+[1] 1
+
+$y
+[1] 1
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, c(list()), c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#Ignored.WrongCaller#
+#.Call(stats:::C_SplineCoef, environment(), c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#Ignored.WrongCaller#
+#.Call(stats:::C_SplineCoef, function() {}, c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#
+#.Call(stats:::C_SplineCoef, list(), c(1:5), c(1:5))
+$method
+[1] NA
+
+$n
+[1] 5
+
+$x
+[1] 1 2 3 4 5
+
+$y
+[1] 1 2 3 4 5
+
+$b
+[1] 0 0 0 0 0
+
+$c
+[1] 0 0 0 0 0
+
+$d
+[1] 0 0 0 0 0
+
+
+##com.oracle.truffle.r.test.library.stats.TestSplineFunctions.basicSplineCoef#Ignored.WrongCaller#
+#.Call(stats:::C_SplineCoef, list(1), c(1), c(1))
+$method
+[1] NA
+
+$n
+[1] 1
+
+$x
+[1] 1
+
+$y
+[1] 1
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+$d
+[1] 0
+
+
 ##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
@@ -136649,6 +138610,130 @@ Levels: 2147483648L
 #type.convert('NA', 1)
 Error in type.convert("NA", 1) : invalid 'na.strings' argument
 
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, NA, 'NA', FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, NULL, 'NA', FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', 'TRUE', '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', 'abc', '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', 1, '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', 2, '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', FALSE, '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', NA, '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', NULL, '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', c(), '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', c(NULL), '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', environment(), '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', function() {}, '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', list('abc'), '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), 'NA', list(), '.', 'allow.loss')
+[1] 1
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), NA, FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), NULL, FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), c(), FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), c(1), FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c('1'), environment(), FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c(), 'NA', FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c(1), c(1), FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c(1, '1'), c(1), FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c(1, 'TRUE'), c(1), FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c(1, 'TRUE', 'x'), c(1), FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c(1, 'x'), c(1), FALSE, '.', 'allow.loss')
+Error: invalid 'na.strings' argument
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, c(1, TRUE), c(1), FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, environment(), 'NA', FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, list('1'), list('1'), FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, list('1'), list(1), FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
+##com.oracle.truffle.r.test.library.utils.TestTypeConvert.typeConvertExternal2Test#
+#.External2(utils:::C_typeconvert, list(1), list(1), FALSE, '.', 'allow.loss')
+Error: the first argument must be of mode character
+
 ##com.oracle.truffle.r.test.library.utils.TestUtils.testHeadNTail#
 #{head(letters)}
 [1] "a" "b" "c" "d" "e" "f"
@@ -136983,6 +139068,195 @@ non-integer value 12345678909876543212L qualified with L; using numeric value
 #'\ ' == ' '
 [1] TRUE
 
+##com.oracle.truffle.r.test.rffi.TestRFFIPackage.TestLENGTH#Output.MayIgnoreErrorContext#
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- list(); x <- x <- append(x, rffi.LENGTH(1)); x <- append(x, rffi.LENGTH(c(1,2,3))); x <- append(x, rffi.LENGTH(list(1,2,3))); x <- append(x, rffi.LENGTH(expression(1,2))); ; detach("package:testrffi", unload=T); x }
+[[1]]
+[1] 1
+
+[[2]]
+[1] 3
+
+[[3]]
+[1] 3
+
+[[4]]
+[1] 2
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testAsFunctions#Output.MayIgnoreWarningContext#
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- list(); x <- x <- append(x, rffi.asChar(1L)); x <- append(x, rffi.asInteger(1L)); x <- append(x, rffi.asReal(1L)); x <- append(x, rffi.asLogical(1L)); x <- append(x, rffi.asChar(2)); x <- append(x, rffi.asInteger(2)); x <- append(x, rffi.asReal(2)); x <- append(x, rffi.asLogical(2)); x <- append(x, rffi.asChar(2.2)); x <- append(x, rffi.asInteger(2.2)); x <- append(x, rffi.asReal(2.2)); x <- append(x, rffi.asLogical(2.2)); x <- append(x, rffi.asChar(T)); x <- append(x, rffi.asInteger(T)); x <- append(x, rffi.asReal(T)); x <- append(x, rffi.asLogical(T)); x <- append(x, rffi.asChar(integer())); x <- append(x, rffi.asInteger(integer())); x <- append(x, rffi.asReal(integer())); x <- append(x, rffi.asLogical(integer())); x <- append(x, rffi.asChar(numeric())); x <- append(x, rffi.asInteger(numeric())); x <- append(x, rffi.asReal(numeric())); x <- append(x, rffi.asLogical(numeric())); x <- append(x, rffi.asChar(logical())); x <- append(x, rffi.asInteger(logical())); x <- append(x, rffi.asReal(logical())); x <- append(x, rffi.asLogical(logical())); x <- append(x, rffi.asChar(character())); x <- append(x, rffi.asInteger(character())); x <- append(x, rffi.asReal(character())); x <- append(x, rffi.asLogical(character())); x <- append(x, rffi.asChar(c(5,6))); x <- append(x, rffi.asInteger(c(5,6))); x <- append(x, rffi.asReal(c(5,6))); x <- append(x, rffi.asLogical(c(5,6))); x <- append(x, rffi.asChar(c(2.3, 3.4))); x <- append(x, rffi.asInteger(c(2.3, 3.4))); x <- append(x, rffi.asReal(c(2.3, 3.4))); x <- append(x, rffi.asLogical(c(2.3, 3.4))); x <- append(x, rffi.asChar(c(T, F))); x <- append(x, rffi.asInteger(c(T, F))); x <- append(x, rffi.asReal(c(T, F))); x <- append(x, rffi.asLogical(c(T, F))); x <- append(x, rffi.asChar(as.symbol("sym"))); x <- append(x, rffi.asInteger(as.symbol("sym"))); x <- append(x, rffi.asReal(as.symbol("sym"))); x <- append(x, rffi.asLogical(as.symbol("sym"))); x <- append(x, rffi.asChar(list())); x <- append(x, rffi.asInteger(list())); x <- append(x, rffi.asReal(list())); x <- append(x, rffi.asLogical(list())); ; detach("package:testrffi", unload=T); x }
+[[1]]
+[1] "1"
+
+[[2]]
+[1] 1
+
+[[3]]
+[1] 1
+
+[[4]]
+[1] TRUE
+
+[[5]]
+[1] "2"
+
+[[6]]
+[1] 2
+
+[[7]]
+[1] 2
+
+[[8]]
+[1] TRUE
+
+[[9]]
+[1] "2.2"
+
+[[10]]
+[1] 2
+
+[[11]]
+[1] 2.2
+
+[[12]]
+[1] TRUE
+
+[[13]]
+[1] "TRUE"
+
+[[14]]
+[1] 1
+
+[[15]]
+[1] 1
+
+[[16]]
+[1] TRUE
+
+[[17]]
+[1] NA
+
+[[18]]
+[1] NA
+
+[[19]]
+[1] NA
+
+[[20]]
+[1] NA
+
+[[21]]
+[1] NA
+
+[[22]]
+[1] NA
+
+[[23]]
+[1] NA
+
+[[24]]
+[1] NA
+
+[[25]]
+[1] NA
+
+[[26]]
+[1] NA
+
+[[27]]
+[1] NA
+
+[[28]]
+[1] NA
+
+[[29]]
+[1] NA
+
+[[30]]
+[1] NA
+
+[[31]]
+[1] NA
+
+[[32]]
+[1] NA
+
+[[33]]
+[1] "5"
+
+[[34]]
+[1] 5
+
+[[35]]
+[1] 5
+
+[[36]]
+[1] TRUE
+
+[[37]]
+[1] "2.3"
+
+[[38]]
+[1] 2
+
+[[39]]
+[1] 2.3
+
+[[40]]
+[1] TRUE
+
+[[41]]
+[1] "TRUE"
+
+[[42]]
+[1] 1
+
+[[43]]
+[1] 1
+
+[[44]]
+[1] TRUE
+
+[[45]]
+[1] "sym"
+
+[[46]]
+[1] NA
+
+[[47]]
+[1] NA
+
+[[48]]
+[1] NA
+
+[[49]]
+[1] NA
+
+[[50]]
+[1] NA
+
+[[51]]
+[1] NA
+
+[[52]]
+[1] NA
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackage.testListFunctions#Output.MayIgnoreErrorContext#
+#{ library("testrffi", lib.loc = "tmptest/com.oracle.truffle.r.test.rpackages"); x <- list(); x <- x <- append(x, rffi.CAR(pairlist(1,2))); x <- append(x, rffi.CDR(pairlist(1,2))); x <- append(x, rffi.CAR(pairlist(x=1L, y=2L))); x <- append(x, rffi.CDR(pairlist(x=1L, y=2L))); ; detach("package:testrffi", unload=T); x }
+[[1]]
+[1] 1
+
+[[2]]
+[1] 2
+
+[[3]]
+[1] 1
+
+$y
+[1] 2
+
+
 ##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", unload=T); x }
 [1] 5
@@ -137193,6 +139467,795 @@ Error in .Call("null", PACKAGE = "foo") :
 #{ 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.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(1L, 0) :
+  cannot coerce type 'integer' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 1); detach('package:testrffi', unload=T); x }
+`1`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 10); detach('package:testrffi', unload=T); x }
+[1] TRUE
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 13); detach('package:testrffi', unload=T); x }
+[1] 1
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 14); detach('package:testrffi', unload=T); x }
+[1] 1
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 15); detach('package:testrffi', unload=T); x }
+[1] 1+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 16); detach('package:testrffi', unload=T); x }
+[1] "1"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 19); detach('package:testrffi', unload=T); x }
+[[1]]
+[1] 1
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(1L, 24); detach('package:testrffi', unload=T); x }
+[1] 01
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(2, 0) :
+  cannot coerce type 'double' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 1); detach('package:testrffi', unload=T); x }
+`2`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 10); detach('package:testrffi', unload=T); x }
+[1] TRUE
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 13); detach('package:testrffi', unload=T); x }
+[1] 2
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 14); detach('package:testrffi', unload=T); x }
+[1] 2
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 15); detach('package:testrffi', unload=T); x }
+[1] 2+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 16); detach('package:testrffi', unload=T); x }
+[1] "2"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 19); detach('package:testrffi', unload=T); x }
+[[1]]
+[1] 2
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 24); detach('package:testrffi', unload=T); x }
+[1] 02
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(2.2, 0) :
+  cannot coerce type 'double' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 1); detach('package:testrffi', unload=T); x }
+`2.2`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 10); detach('package:testrffi', unload=T); x }
+[1] TRUE
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 13); detach('package:testrffi', unload=T); x }
+[1] 2
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 14); detach('package:testrffi', unload=T); x }
+[1] 2.2
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 15); detach('package:testrffi', unload=T); x }
+[1] 2.2+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 16); detach('package:testrffi', unload=T); x }
+[1] "2.2"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 19); detach('package:testrffi', unload=T); x }
+[[1]]
+[1] 2.2
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 24); detach('package:testrffi', unload=T); x }
+[1] 02
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(T, 0) :
+  cannot coerce type 'logical' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 1); detach('package:testrffi', unload=T); x }
+`TRUE`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 10); detach('package:testrffi', unload=T); x }
+[1] TRUE
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 13); detach('package:testrffi', unload=T); x }
+[1] 1
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 14); detach('package:testrffi', unload=T); x }
+[1] 1
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 15); detach('package:testrffi', unload=T); x }
+[1] 1+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 16); detach('package:testrffi', unload=T); x }
+[1] "TRUE"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 19); detach('package:testrffi', unload=T); x }
+[[1]]
+[1] TRUE
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 24); detach('package:testrffi', unload=T); x }
+[1] 01
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(c(2.3, 3.4), 0) :
+  cannot coerce type 'double' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 1); detach('package:testrffi', unload=T); x }
+`2.3`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 10); detach('package:testrffi', unload=T); x }
+[1] TRUE TRUE
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 13); detach('package:testrffi', unload=T); x }
+[1] 2 3
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 14); detach('package:testrffi', unload=T); x }
+[1] 2.3 3.4
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 15); detach('package:testrffi', unload=T); x }
+[1] 2.3+0i 3.4+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 16); detach('package:testrffi', unload=T); x }
+[1] "2.3" "3.4"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 19); detach('package:testrffi', unload=T); x }
+[[1]]
+[1] 2.3
+
+[[2]]
+[1] 3.4
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 24); detach('package:testrffi', unload=T); x }
+[1] 02 03
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(c(5, 6), 0) :
+  cannot coerce type 'double' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 1); detach('package:testrffi', unload=T); x }
+`5`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 10); detach('package:testrffi', unload=T); x }
+[1] TRUE TRUE
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 13); detach('package:testrffi', unload=T); x }
+[1] 5 6
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 14); detach('package:testrffi', unload=T); x }
+[1] 5 6
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 15); detach('package:testrffi', unload=T); x }
+[1] 5+0i 6+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 16); detach('package:testrffi', unload=T); x }
+[1] "5" "6"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 19); detach('package:testrffi', unload=T); x }
+[[1]]
+[1] 5
+
+[[2]]
+[1] 6
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 24); detach('package:testrffi', unload=T); x }
+[1] 05 06
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(c(T, F), 0) :
+  cannot coerce type 'logical' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 1); detach('package:testrffi', unload=T); x }
+`TRUE`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 10); detach('package:testrffi', unload=T); x }
+[1]  TRUE FALSE
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 13); detach('package:testrffi', unload=T); x }
+[1] 1 0
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 14); detach('package:testrffi', unload=T); x }
+[1] 1 0
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 15); detach('package:testrffi', unload=T); x }
+[1] 1+0i 0+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 16); detach('package:testrffi', unload=T); x }
+[1] "TRUE"  "FALSE"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 19); detach('package:testrffi', unload=T); x }
+[[1]]
+[1] TRUE
+
+[[2]]
+[1] FALSE
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 24); detach('package:testrffi', unload=T); x }
+[1] 01 00
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(character(), 0) :
+  cannot coerce type 'character' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 1); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(character(), 1) :
+  invalid data of mode 'character' (too short)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 10); detach('package:testrffi', unload=T); x }
+logical(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 13); detach('package:testrffi', unload=T); x }
+integer(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 14); detach('package:testrffi', unload=T); x }
+numeric(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 15); detach('package:testrffi', unload=T); x }
+complex(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 16); detach('package:testrffi', unload=T); x }
+character(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 19); detach('package:testrffi', unload=T); x }
+list()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 24); detach('package:testrffi', unload=T); x }
+raw(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(integer(), 0) :
+  cannot coerce type 'integer' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 1); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(integer(), 1) :
+  invalid data of mode 'integer' (too short)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 10); detach('package:testrffi', unload=T); x }
+logical(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 13); detach('package:testrffi', unload=T); x }
+integer(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 14); detach('package:testrffi', unload=T); x }
+numeric(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 15); detach('package:testrffi', unload=T); x }
+complex(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 16); detach('package:testrffi', unload=T); x }
+character(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 19); detach('package:testrffi', unload=T); x }
+list()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 24); detach('package:testrffi', unload=T); x }
+raw(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(list(), 0) :
+  unimplemented type 'list' in 'coerceVectorList'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 1); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(list(), 1) :
+  invalid type/length (symbol/0) in vector allocation
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 10); detach('package:testrffi', unload=T); x }
+logical(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 13); detach('package:testrffi', unload=T); x }
+integer(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 14); detach('package:testrffi', unload=T); x }
+numeric(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 15); detach('package:testrffi', unload=T); x }
+complex(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 16); detach('package:testrffi', unload=T); x }
+character(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 19); detach('package:testrffi', unload=T); x }
+list()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 24); detach('package:testrffi', unload=T); x }
+raw(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(logical(), 0) :
+  cannot coerce type 'logical' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 1); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(logical(), 1) :
+  invalid data of mode 'logical' (too short)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 10); detach('package:testrffi', unload=T); x }
+logical(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 13); detach('package:testrffi', unload=T); x }
+integer(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 14); detach('package:testrffi', unload=T); x }
+numeric(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 15); detach('package:testrffi', unload=T); x }
+complex(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 16); detach('package:testrffi', unload=T); x }
+character(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 19); detach('package:testrffi', unload=T); x }
+list()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 24); detach('package:testrffi', unload=T); x }
+raw(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(numeric(), 0) :
+  cannot coerce type 'double' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 1); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(numeric(), 1) :
+  invalid data of mode 'double' (too short)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 10); detach('package:testrffi', unload=T); x }
+logical(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 13); detach('package:testrffi', unload=T); x }
+integer(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 14); detach('package:testrffi', unload=T); x }
+numeric(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 15); detach('package:testrffi', unload=T); x }
+complex(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 16); detach('package:testrffi', unload=T); x }
+character(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 19); detach('package:testrffi', unload=T); x }
+list()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 24); detach('package:testrffi', unload=T); x }
+raw(0)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(structure(1L, names = "a", dim = c(1, 1), myattr = "q"),  :
+  cannot coerce type 'integer' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 1); detach('package:testrffi', unload=T); x }
+`1`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 10); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] TRUE
+attr(,"names")
+[1] "a"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 13); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]    1
+attr(,"names")
+[1] "a"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 14); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]    1
+attr(,"names")
+[1] "a"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 15); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] 1+0i
+attr(,"names")
+[1] "a"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 16); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] "1"
+attr(,"names")
+[1] "a"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 19); detach('package:testrffi', unload=T); x }
+$a
+[1] 1
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(1L,names='a',dim=c(1,1),myattr='q'), 24); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]   01
+attr(,"names")
+[1] "a"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(structure(2.2, names = "b", dim = c(1, 1),  :
+  cannot coerce type 'double' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 1); detach('package:testrffi', unload=T); x }
+`2.2`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 10); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] TRUE
+attr(,"names")
+[1] "b"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 13); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]    2
+attr(,"names")
+[1] "b"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 14); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]  2.2
+attr(,"names")
+[1] "b"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 15); detach('package:testrffi', unload=T); x }
+       [,1]
+[1,] 2.2+0i
+attr(,"names")
+[1] "b"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 16); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] "2.2"
+attr(,"names")
+[1] "b"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 19); detach('package:testrffi', unload=T); x }
+$b
+[1] 2.2
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 24); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]   02
+attr(,"names")
+[1] "b"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(structure(T, names = "c", dim = c(1, 1), myattr = "q"),  :
+  cannot coerce type 'logical' to vector of type 'NULL'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 1); detach('package:testrffi', unload=T); x }
+`TRUE`
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 10); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] TRUE
+attr(,"names")
+[1] "c"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 13); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]    1
+attr(,"names")
+[1] "c"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 14); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]    1
+attr(,"names")
+[1] "c"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 15); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] 1+0i
+attr(,"names")
+[1] "c"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 16); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] "TRUE"
+attr(,"names")
+[1] "c"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 19); detach('package:testrffi', unload=T); x }
+$c
+[1] TRUE
+
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 24); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,]   01
+attr(,"names")
+[1] "c"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 0); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(structure(list(1, "42"), names = c("q", "w"),  :
+  unimplemented type 'list' in 'coerceVectorList'
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 1); detach('package:testrffi', unload=T); x }
+Error in rffi.coerceVector(structure(list(1, "42"), names = c("q", "w"),  :
+  invalid type/length (symbol/2) in vector allocation
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 10); detach('package:testrffi', unload=T); x }
+   q    w
+TRUE   NA
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 13); detach('package:testrffi', unload=T); x }
+ q  w
+ 1 42
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 14); detach('package:testrffi', unload=T); x }
+ q  w
+ 1 42
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 15); detach('package:testrffi', unload=T); x }
+    q     w
+ 1+0i 42+0i
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 16); detach('package:testrffi', unload=T); x }
+   q    w
+ "1" "42"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 19); detach('package:testrffi', unload=T); x }
+     [,1]
+[1,] 1
+[2,] "42"
+attr(,"names")
+[1] "q" "w"
+attr(,"myattr")
+[1] "q"
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVector#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q'), 24); detach('package:testrffi', unload=T); x }
+ q  w
+01 2a
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2, 20); detach('package:testrffi', unload=T); x }
+expression(2)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(2.2, 20); detach('package:testrffi', unload=T); x }
+expression(2.2)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(T, 20); detach('package:testrffi', unload=T); x }
+expression(TRUE)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(2.3, 3.4), 20); detach('package:testrffi', unload=T); x }
+expression(2.3, 3.4)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(5,6), 20); detach('package:testrffi', unload=T); x }
+expression(5, 6)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(c(T, F), 20); detach('package:testrffi', unload=T); x }
+expression(TRUE, FALSE)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(character(), 20); detach('package:testrffi', unload=T); x }
+expression()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(integer(), 20); detach('package:testrffi', unload=T); x }
+expression()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(list(), 20); detach('package:testrffi', unload=T); x }
+expression()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(logical(), 20); detach('package:testrffi', unload=T); x }
+expression()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(numeric(), 20); detach('package:testrffi', unload=T); x }
+expression()
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(2.2, names='b',dim=c(1,1),myattr='q'), 20); detach('package:testrffi', unload=T); x }
+expression(2.2)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Output.IgnoreErrorMessage#Output.MayIgnoreWarningContext#Output.MayIgnoreErrorContext#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(T, names='c',dim=c(1,1),myattr='q'), 20); detach('package:testrffi', unload=T); x }
+expression(TRUE)
+
+##com.oracle.truffle.r.test.rffi.TestRFFIPackageCoercions.testCoerceVectorToExpression#Ignored.Unimplemented#
+#{ library('testrffi', lib.loc = 'tmptest/com.oracle.truffle.r.test.rpackages'); x <- rffi.coerceVector(structure(list(1,'x'), names=c('q','w'),dim=c(2,1),myattr='q'), 20); detach('package:testrffi', unload=T); x }
+expression(q = 1, w = "x")
+attr(,"names")
+[1] "q" "w"
+attr(,"myattr")
+[1] "q"
+
 ##com.oracle.truffle.r.test.rffi.TestUserRNG.testUserRNG#
 #{ dyn.load("com.oracle.truffle.r.test.native/urand/lib/liburand.so"); RNGkind("user"); print(RNGkind()); set.seed(4567); runif(10) }
 [1] "user-supplied" "Inversion"
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
index 7909f4fa60e7b4135016253271c9878c3eb420a3..8d04aedae7d37393be8bb78353d4cf15002c0aa6 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
@@ -853,6 +853,7 @@ public class TestBase {
         microTestInfo.expression = input;
         String result;
         try {
+            beforeEval();
             result = fastROutputManager.fastRSession.eval(this, input, contextInfo, longTimeout);
         } catch (Throwable e) {
             String clazz;
@@ -888,11 +889,11 @@ public class TestBase {
      * we go via the {@code system2} R function (which may call {@link ProcessBuilder} internally).
      *
      */
-    protected static Object evalInstallPackage(String system2Command) throws Throwable {
+    protected static String evalInstallPackage(String system2Command) throws Throwable {
         if (generatingExpected()) {
             return expectedOutputManager.getRSession().eval(null, system2Command, null, true);
         } else {
-            return fastROutputManager.fastRSession.evalAsObject(null, system2Command, null, true);
+            return fastROutputManager.fastRSession.eval(null, system2Command, null, true);
         }
     }
 
@@ -900,7 +901,7 @@ public class TestBase {
      * Evaluate expected output from {@code input}. By default the lookup is based on {@code input}
      * but can be overridden by providing a non-null {@code testIdOrNull}.
      */
-    protected static String expectedEval(String input, TestTrait... traits) {
+    protected String expectedEval(String input, TestTrait... traits) {
         if (generatingExpected()) {
             // generation mode
             return genTestResult(input, traits);
@@ -920,8 +921,8 @@ public class TestBase {
         }
     }
 
-    private static String genTestResult(String input, TestTrait... traits) {
-        return expectedOutputManager.genTestResult(testElementName, input, localDiagnosticHandler, expectedOutputManager.checkOnly, keepTrailingWhiteSpace, traits);
+    private String genTestResult(String input, TestTrait... traits) {
+        return expectedOutputManager.genTestResult(this, testElementName, input, localDiagnosticHandler, expectedOutputManager.checkOnly, keepTrailingWhiteSpace, traits);
     }
 
     /**
@@ -1027,6 +1028,12 @@ public class TestBase {
                 System.out.printf("    failed: %6d | %6d%n", failedTestCount, failedInputCount);
             }
         });
+    }
 
+    /**
+     * Called before an actual evaluation happens.
+     */
+    public void beforeEval() {
+        // empty
     }
 }
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 fa7e505aaa8b009ba6685d60ae52ebbfb31484bd..551890dda835ba3c7345b6594e5993e9160986c6 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
@@ -109,8 +109,7 @@ public class TestBuiltin_ascharacter extends TestBase {
 
     @Test
     public void testascharacter19() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(list(structure(list(given = c('George', 'E.', 'P.'), family = 'Box', role = NULL, email = NULL, comment = NULL), .Names = c('given', 'family', 'role', 'email', 'comment')), structure(list(given = c('David', 'R.'), family = 'Cox', role = NULL, email = NULL, comment = NULL), .Names = c('given', 'family', 'role', 'email', 'comment'))), class = 'person'));as.character(argv[[1]]);");
+        assertEval("argv <- list(structure(list(structure(list(given = c('George', 'E.', 'P.'), family = 'Box', role = NULL, email = NULL, comment = NULL), .Names = c('given', 'family', 'role', 'email', 'comment')), structure(list(given = c('David', 'R.'), family = 'Cox', role = NULL, email = NULL, comment = NULL), .Names = c('given', 'family', 'role', 'email', 'comment'))), class = 'person'));as.character(argv[[1]]);");
     }
 
     @Test
@@ -175,7 +174,7 @@ public class TestBuiltin_ascharacter extends TestBase {
 
     @Test
     public void testascharacter32() {
-        assertEval(Ignored.Unknown, "argv <- list(structure(1:4, class = 'roman'));as.character(argv[[1]]);");
+        assertEval("argv <- list(structure(1:4, class = 'roman'));as.character(argv[[1]]);");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java
index 95b6ce40cdbe5442990d31fa483f141e632c6951..063819596e5ef87e2dabae41d85b56728fbaa3a5 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@ public class TestBuiltin_asfunction extends TestBase {
         assertEval("{ as.function(alist(\"foo\"))() }");
         assertEval("{ as.function(alist(7+42i))() }");
         assertEval("{ as.function(alist(as.raw(7)))() }");
-        assertEval(Output.IgnoreErrorContext, "{ .Internal(as.function.default(alist(a+b), \"foo\")) }");
+        assertEval("{ .Internal(as.function.default(alist(a+b), \"foo\")) }");
         assertEval(Output.IgnoreErrorContext, "{ .Internal(as.function.default(function() 42, parent.frame())) }");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asraw.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asraw.java
index 0de508e8b10e1ccbc7d53677626bc09affe760d6..cd7d0198a34beb1d9641563e31ec0d82da549305 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asraw.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asraw.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -68,5 +68,7 @@ public class TestBuiltin_asraw extends TestBase {
         assertEval(Output.IgnoreWarningContext, "{ as.raw(c(1,1000,NA)) }");
         assertEval(Output.IgnoreWarningContext, "{ as.raw(c(1L, -2L, 3L)) }");
         assertEval(Output.IgnoreWarningContext, "{ as.raw(c(1L, -2L, NA)) }");
+        assertEval(Output.IgnoreWarningContext, "{ as.raw('10000001') }");
+        assertEval(Output.IgnoreWarningContext, "{ as.raw(c('10000001', '42')) }");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java
index 6ebebb950d5909849c7a6b02cf45733ff75c3941..671161d6d806b1213fdbc8037f30ee9fb5a8aa09 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java
@@ -422,9 +422,9 @@ public class TestBuiltin_asvector extends TestBase {
         assertEval("as.vector(x~z)");
         assertEval("as.vector(file(''))");
 
-        assertEval(Output.IgnoreErrorContext, "{ as.vector(42, NULL) }");
-        assertEval(Output.IgnoreErrorContext, "{ as.vector(42, c(\"character\", \"character\")) }");
-        assertEval(Output.IgnoreErrorContext, "{ as.vector(42, character())  }");
+        assertEval("{ as.vector(42, NULL) }");
+        assertEval("{ as.vector(42, c(\"character\", \"character\")) }");
+        assertEval("{ as.vector(42, character())  }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java
index d57ec648caec733d2989765330272e9ae9f3d466..d39f463f15a32fc012ce216b0797e9f95b6d16e2 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cbind.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -92,5 +92,85 @@ public class TestBuiltin_cbind extends TestBase {
         assertEval("cbind(character(0), 'f')");
         assertEval("cbind(55, character(0))");
         assertEval("cbind(a=55, character(0))");
+
+        assertEval("v <- 1; attr(v, 'a') <- 'a'; cbind(v); cbind(v, v)");
+        assertEval("v <- 1; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; cbind(v); cbind(v, v)");
+        assertEval("v <- 1:3; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; cbind(v); cbind(v, v)");
+        assertEval("v <- 1:3; v1<-1:3; attr(v, 'a') <- 'a'; attr(v1, 'a1') <- 'a1'; cbind(v, v1)");
+    }
+
+    @Test
+    public void testGenericDispatch() {
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(...) 'foo'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(...) 'foo'; v2 <- 1; class(v2) <- 'foo'; cbind(v2) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; assign('cbind.foo', function(x) {'foo'}, envir=.__S3MethodsTable__.); result <- cbind(v) ; rm('cbind.foo', envir=.__S3MethodsTable__.); result;}");
+
+        // segfault in gnur
+        assertEval(Ignored.ReferenceError, "{ v <- 1; class(v) <- 'foo'; cbind.foo <- length; cbind(v) }");
+
+        assertEval(Output.IgnoreErrorContext, "{ v <- 1; class(v) <- 'foo'; cbind.foo <- rawToBits; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind(v) }");
+        assertEval("{ v <- 1; cbind.foo <- function(...) 'foo'; cbind(v) }");
+
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(deparse.level, ...) 'foo'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(deparse.level, x) 'foo'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(deparse.level, x1, x2) 'foo'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(x0, deparse.level, x1, x2) 'foo'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(x0, x1, x2) 'foo'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; cbind.foo <- function(x) 'foo'; cbind(v) }");
+        assertEval(Ignored.WrongCaller, "{ v <- 1; class(v) <- 'foo'; cbind.foo <- function() 'foo'; cbind(v) }");
+
+        assertEval("{ v <- 1; class(v) <- c('foo1', 'foo2'); cbind.foo1 <- function(...) 'foo1'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- c('foo1', 'foo2'); cbind.foo2 <- function(...) 'foo2'; cbind(v) }");
+        assertEval("{ v <- 1; class(v) <- c('foo1', 'foo2'); cbind.foo1 <- function(...) 'foo1'; cbind.foo2 <- function(...) 'foo2'; cbind(v) }");
+
+        assertEval("{ v1 <- 1; class(v1) <- 'foo1'; cbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; cbind.foo2 <- function(...) 'foo2'; cbind(v1, v2) }");
+        assertEval("{ v1 <- 1; class(v1) <- 'foo1'; cbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; cbind(v1, v2) }");
+        assertEval("{ v1 <- 1; class(v1) <- 'foo1'; v2 <- 2; class(v2) <- 'foo2'; cbind.foo2 <- function(...) 'foo2'; cbind(v1, v2) }");
+    }
+
+    @Test
+    public void testDimnames() {
+        assertEval("{ attributes(cbind(integer(0))) }");
+        assertEval("{ attributes(cbind(list())) }");
+        assertEval("{ attributes(cbind(matrix())) }");
+        assertEval("{ attributes(cbind(1L)) }");
+        assertEval("{ attributes(cbind(c(1L, 2L))) }");
+        assertEval("{ attributes(cbind(list(1L, 2L))) }");
+        assertEval("{ attributes(cbind(matrix(1L, 2L))) }");
+        assertEval("{ attributes(cbind(1L, 2L)) }");
+
+        assertEval("{ cbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L) }");
+        assertEval("{ cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L) }");
+        assertEval("{ cbind(structure(1:4, dim=c(2,2)), 1L) }");
+
+        assertEval("{ attributes(cbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L)) }");
+        assertEval("{ attributes(cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L)) }");
+        assertEval("{ attributes(cbind(structure(1:4, dim=c(2,2)), 1L)) }");
+
+        assertEval("{ cbind(NULL, integer(0)) }");
+        assertEval("{ cbind(integer(0), integer(0)) }");
+        assertEval("{ cbind(c(1), integer(0)) }");
+        assertEval("{ cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0)) }");
+
+        assertEval("{ attributes(cbind(NULL, integer(0))) }");
+        assertEval("{ attributes(cbind(integer(0), integer(0))) }");
+        assertEval("{ attributes(cbind(c(1), integer(0))) }");
+        assertEval("{ attributes(cbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0))) }");
+    }
+
+    @Test
+    public void testRetType() {
+        assertEval("dput(cbind(NULL))");
+        assertEval("dput(cbind(NULL, integer(0)))");
+        assertEval("dput(cbind(NULL, NULL, integer(0)))");
+        assertEval("dput(cbind(NULL, NULL, double(0)))");
+        assertEval("dput(cbind(NULL, NULL, integer(0), double(0)))");
+        assertEval("dput(cbind(NULL, NULL, double(0), integer(0)))");
+        assertEval("dput(cbind(NULL, NULL, double(0), character(0)))");
+        assertEval("dput(cbind(NULL, NULL, double(0), integer(0), character(0)))");
+        assertEval("dput(cbind(c(NULL, NULL), integer(0)))");
+        assertEval("dput(cbind(integer(0)))");
+        assertEval("dput(cbind(integer(0), NULL, NULL))");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java
index b1d19e945d05d1bb20551aa2f3eb906fe4bd6f31..70eb09d7837341c519da3734844e11d30cc5d755 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -276,6 +276,13 @@ public class TestBuiltin_deparse extends TestBase {
                     "-0.0000000000000001", "-1.545234523452345252523452345", "-Inf", "c(1L,2L,3L)", "c(1,2,3)", "c(NA_integer_, 1L,2L,3L)", "c(1L,2L,3L, NA_integer_)", "c(3L,2L,1L)",
                     "c(-2L,-1L,0L,1L)"};
 
+    @Test
+    public void testDeparseStructure() {
+        assertEval("{ deparse(structure(.Data=c(1,2))) }");
+        assertEval("{ deparse(structure(.Data=c(1,2), attr1=c(1))) }");
+        assertEval("{ deparse(structure(.Data=c(1,2), attr1=c(1), attr2=c(2))) }");
+    }
+
     @Test
     public void testDeparse() {
         assertEval(template("deparse(%0)", VALUES));
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java
index 8ef63beb180da0d71c6edd5735e613932e97e0b5..d783aa1d15d5436a5548a211a07b20f9e9ec8603 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -311,5 +311,6 @@ public class TestBuiltin_format extends TestBase {
         assertEval("{ format(c(7,42)) }");
         assertEval("{ format(c(7.42,42.7)) }");
         assertEval("{ format(c(7.42,42.7,NA)) }");
+        assertEval("{ .Internal(format(.GlobalEnv,FALSE,NA,0,0,3,TRUE,NA,'.')) }");
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadArgumentNode.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isSingle.java
similarity index 59%
rename from com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadArgumentNode.java
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isSingle.java
index 8bfa60d8c2f2639aea02d886ec89ec99ef009234..bfa7a01befb821e47f32eefe4daa6be549f408ae 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadArgumentNode.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_isSingle.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,33 +20,36 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.nodes.access;
+package com.oracle.truffle.r.test.builtins;
 
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.runtime.RArguments;
-import com.oracle.truffle.r.runtime.nodes.RNode;
+import org.junit.Test;
 
-class ReadArgumentNode extends RNode {
+import com.oracle.truffle.r.test.TestBase;
 
-    private final int index;
+public class TestBuiltin_isSingle extends TestBase {
 
-    protected ReadArgumentNode(int index) {
-        this.index = index;
+    @Test
+    public void testisSingle0() {
+        assertEval("is.single");
     }
 
-    /**
-     * for WrapperNode subclass.
-     */
-    protected ReadArgumentNode() {
-        index = 0;
+    @Test
+    public void testisSingle1() {
+        assertEval("is.single()");
     }
 
-    @Override
-    public Object execute(VirtualFrame frame) {
-        return RArguments.getArgument(frame, index);
+    @Test
+    public void testisSingle2() {
+        assertEval("is.single(0)");
     }
 
-    public int getIndex() {
-        return index;
+    @Test
+    public void testisSingle3() {
+        assertEval("is.single(NULL)");
+    }
+
+    @Test
+    public void testisSingle4() {
+        assertEval("is.single(+)");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
index e612304d8f81c89851fe5e590a4f2646a6b5b891..28dbce4917542c18370338302cbfb1966da87a9e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -60,7 +60,7 @@ public class TestBuiltin_list extends TestBase {
 
     @Test
     public void testlist9() {
-        assertEval("argv <- list(label = '', x = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), just = 'centre', hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = NULL, gp = structure(list(), class = 'gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]]);");
+        assertEval("argv <- list(label = '', x = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), just = 'centre', hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = NULL, gp = structure(list(), class = 'r_gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]]);");
     }
 
     @Test
@@ -237,7 +237,7 @@ public class TestBuiltin_list extends TestBase {
 
     @Test
     public void testlist43() {
-        assertEval("argv <- list(raster = structure('#000000', .Dim = c(1L, 1L), class = 'raster'), x = structure(0, unit = 'npc', valid.unit = 0L, class = 'unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), width = NULL, height = NULL, just = 'centre', hjust = NULL, vjust = NULL, interpolate = TRUE, name = NULL, gp = structure(list(), class = 'gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]],argv[[12]]);");
+        assertEval("argv <- list(raster = structure('#000000', .Dim = c(1L, 1L), class = 'r_raster'), x = structure(0, unit = 'npc', valid.unit = 0L, class = 'r_unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), width = NULL, height = NULL, just = 'centre', hjust = NULL, vjust = NULL, interpolate = TRUE, name = NULL, gp = structure(list(), class = 'r_gpar'), vp = NULL);list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]],argv[[6]],argv[[7]],argv[[8]],argv[[9]],argv[[10]],argv[[11]],argv[[12]]);");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java
index 8acdd22dea89864a1f5f08de95ca98fbb8d93eb8..1d26cefe1010e25bc9e349863b35c87544bead8b 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java
@@ -610,8 +610,7 @@ public class TestBuiltin_operators extends TestBase {
 
     @Test
     public void testoperators118() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(c('white', 'aquamarine3', 'bisque2', 'blueviolet', 'burlywood4', 'chartreuse4', 'coral4', 'cyan3', 'darkgreen', 'darkorange1', 'aliceblue', 'white', 'white', 'white', 'white', 'chocolate', 'cornflowerblue', 'cyan4', 'darkgrey', 'darkorange2', 'antiquewhite', 'white', 'white', 'white', 'white', 'chocolate1', 'cornsilk', 'darkblue', 'darkkhaki', 'darkorange3', 'antiquewhite1', 'white', 'white', 'white', 'white', 'chocolate2', 'cornsilk1', 'darkcyan', 'darkmagenta', 'darkorange4', 'antiquewhite2', 'azure2', 'blanchedalmond', 'brown3', 'cadetblue3', 'chocolate3', 'cornsilk2', 'darkgoldenrod', 'darkolivegreen', 'darkorchid', 'antiquewhite3', 'azure3', 'blue', 'brown4', 'cadetblue4', 'chocolate4', 'cornsilk3', 'darkgoldenrod1', 'darkolivegreen1', 'darkorchid1', 'antiquewhite4', 'azure4', 'blue1', 'burlywood', 'chartreuse', 'coral', 'cornsilk4', 'darkgoldenrod2', 'darkolivegreen2', 'darkorchid2', 'aquamarine', 'beige', 'blue2', 'burlywood1', 'chartreuse1', 'coral1', 'cyan', 'darkgoldenrod3', 'darkolivegreen3', 'darkorchid3', 'aquamarine1', 'bisque', 'blue3', 'burlywood2', 'chartreuse2', 'coral2', 'cyan1', 'darkgoldenrod4', 'darkolivegreen4', 'darkorchid4', 'aquamarine2', 'bisque1', 'blue4', 'burlywood3', 'chartreuse3', 'coral3', 'cyan2', 'darkgray', 'darkorange', 'darkred'), .Dim = c(10L, 10L), class = 'raster'), 'white');`==`(argv[[1]],argv[[2]]);");
+        assertEval("argv <- list(structure(c('white', 'aquamarine3', 'bisque2', 'blueviolet', 'burlywood4', 'chartreuse4', 'coral4', 'cyan3', 'darkgreen', 'darkorange1', 'aliceblue', 'white', 'white', 'white', 'white', 'chocolate', 'cornflowerblue', 'cyan4', 'darkgrey', 'darkorange2', 'antiquewhite', 'white', 'white', 'white', 'white', 'chocolate1', 'cornsilk', 'darkblue', 'darkkhaki', 'darkorange3', 'antiquewhite1', 'white', 'white', 'white', 'white', 'chocolate2', 'cornsilk1', 'darkcyan', 'darkmagenta', 'darkorange4', 'antiquewhite2', 'azure2', 'blanchedalmond', 'brown3', 'cadetblue3', 'chocolate3', 'cornsilk2', 'darkgoldenrod', 'darkolivegreen', 'darkorchid', 'antiquewhite3', 'azure3', 'blue', 'brown4', 'cadetblue4', 'chocolate4', 'cornsilk3', 'darkgoldenrod1', 'darkolivegreen1', 'darkorchid1', 'antiquewhite4', 'azure4', 'blue1', 'burlywood', 'chartreuse', 'coral', 'cornsilk4', 'darkgoldenrod2', 'darkolivegreen2', 'darkorchid2', 'aquamarine', 'beige', 'blue2', 'burlywood1', 'chartreuse1', 'coral1', 'cyan', 'darkgoldenrod3', 'darkolivegreen3', 'darkorchid3', 'aquamarine1', 'bisque', 'blue3', 'burlywood2', 'chartreuse2', 'coral2', 'cyan1', 'darkgoldenrod4', 'darkolivegreen4', 'darkorchid4', 'aquamarine2', 'bisque1', 'blue4', 'burlywood3', 'chartreuse3', 'coral3', 'cyan2', 'darkgray', 'darkorange', 'darkred'), .Dim = c(10L, 10L), class = 'raster'), 'white');`==`(argv[[1]],argv[[2]]);");
     }
 
     @Test
@@ -1926,6 +1925,13 @@ public class TestBuiltin_operators extends TestBase {
                         "data[c('a','b')] + 1; 1 + data[c('a','b')]; data[c('a','b')] + c(1,2); c(1,2) + data[c('a','b')]");
     }
 
+    @Test
+    public void testBooleanOperators() {
+        // tests that deparse in as.symbol removes backticks
+        assertEval("as.symbol('*') == '*'");
+        assertEval("as.symbol('<-') == '<-'");
+    }
+
     @Test
     public void testOperators() {
         assertEval("{ `+`(1,2) }");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_parse.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_parse.java
index 748403bf04222400b0c2d1518b2ae61633adff42..bee6607ab3cf968740191301de0ff56c2facb8a3 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_parse.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_parse.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -57,4 +57,9 @@ public class TestBuiltin_parse extends TestBase {
     public void testArgumentsCasts() {
         assertEval(".Internal(parse(stdin(), c(1,2), c('expr1', 'expr2'), '?', '<weird-text', 'unknown'))");
     }
+
+    @Test
+    public void testSrcfile() {
+        assertEval("parse(text='', srcfile=srcfile(system.file('testfile')))");
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java
index 1aadc8d800a701136be7930ce580f038f44d5349..15183cd6f32c514481cd5d217b543b0ca0f95b49 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_paste.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -81,4 +81,15 @@ public class TestBuiltin_paste extends TestBase {
         assertEval("{ paste(sep=\"\") }");
         assertEval("{ paste(1:2, 1:3, FALSE, collapse=\"-\", sep=\"+\") }");
     }
+
+    @Test
+    public void testPasteWithS3AsCharacter() {
+        // Note the catch: class on strings is ignored....
+        assertEval("{ as.character.myc <- function(x) '42'; val <- 'hello'; class(val) <- 'myc'; paste(val, 'world') }");
+        // Next 2 tests should show error since 42, nor NULL is not character
+        assertEval("{ as.character.myc <- function(x) 42; val <- 3.14; class(val) <- 'myc'; paste(val, 'world') }");
+        assertEval("{ as.character.myc <- function(x) NULL; val <- 3.14; class(val) <- 'myc'; paste(val, 'world') }");
+        assertEval("{ as.character.myc <- function(x) '42'; val <- 3.14; class(val) <- 'myc'; paste(val, 'world') }");
+        assertEval("{ assign('as.character.myc', function(x) '42', envir=.__S3MethodsTable__.); val <- 3.14; class(val) <- 'myc'; res <- paste(val, 'world'); rm('as.character.myc', envir=.__S3MethodsTable__.); res }");
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_quit.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_quit.java
index face212e7294372db312b4169fba1f6079d17338..28562baadd09d6ca16c269da44e0280629b73ade 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_quit.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_quit.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,14 +22,79 @@
  */
 package com.oracle.truffle.r.test.builtins;
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.oracle.truffle.r.test.TestBase;
 
 public class TestBuiltin_quit extends TestBase {
 
+    private static final Path PATH_RDATA = Paths.get(".RData");
+    private static final Path PATH_RHISTORY = Paths.get(".Rhistory");
+    private static final Path PATH_RDATA_BAK = PATH_RDATA.resolveSibling(PATH_RDATA.getFileName() + ".bak");
+    private static final Path PATH_RHISTORY_BAK = PATH_RHISTORY.resolveSibling(PATH_RHISTORY.getFileName() + ".bak");
+
+    /**
+     * Test case {@link #testQuitEmptyEnv()} possibly destroys previously stored sessions. If so,
+     * first backup {@code .RData} and {@code .Rhistory}.
+     *
+     * @throws IOException
+     */
+    @BeforeClass
+    public static void backupHistory() throws IOException {
+        if (Files.exists(PATH_RDATA)) {
+            move(PATH_RDATA, PATH_RDATA_BAK);
+        }
+        if (Files.exists(PATH_RHISTORY)) {
+            move(PATH_RHISTORY, PATH_RHISTORY_BAK);
+        }
+    }
+
+    private static void move(Path pathRData, Path dest) throws IOException {
+
+        Files.move(pathRData, dest, StandardCopyOption.REPLACE_EXISTING);
+    }
+
     @Test
     public void testQuitErrorSave() {
         assertEval("{ quit(\"xx\") }");
     }
+
+    @Test
+    public void testQuitEmptyEnv() {
+        assertEval("{ quit(\"yes\") }");
+    }
+
+    /**
+     * Removes temporarily created files {@code .RData} and {@code .Rhistory} and restore backups if
+     * available.
+     * 
+     * @throws IOException
+     */
+    @AfterClass
+    public static void restoreHistory() throws IOException {
+
+        // remove any created ".RData" and ".Rhistory" file
+        if (Files.exists(PATH_RDATA)) {
+            Files.delete(PATH_RDATA);
+        }
+        if (Files.exists(PATH_RHISTORY)) {
+            Files.delete(PATH_RHISTORY);
+        }
+
+        // restore previously rescued files
+        if (Files.exists(PATH_RDATA_BAK)) {
+            move(PATH_RDATA_BAK, PATH_RDATA);
+        }
+        if (Files.exists(PATH_RHISTORY_BAK)) {
+            move(PATH_RHISTORY_BAK, PATH_RHISTORY);
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java
index 0eae3eaab5cacd9b8cf6ee22767d8f741c073f32..46cd9ba2ed297edc052f85606e5b4bc15a42af6c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -156,4 +156,25 @@ public class TestBuiltin_range extends TestBase {
     public void testrange31() {
         assertEval("argv <- list(structure(c(1, 0.666666666666667, 0.333333333333333, 0, -0.333333333333333, -0.666666666666667, -1, -1.33333333333333, -1.66666666666667, 1.5, 1, 0.5, 0, -0.5, -1, -1.5, -2, -2.5, 3, 2, 1, 0, -1, -2, -3, -4, -5, -Inf, -Inf, -Inf, NaN, Inf, Inf, Inf, Inf, Inf, -3, -2, -1, 0, 1, 2, 3, 4, 5, -1.5, -1, -0.5, 0, 0.5, 1, 1.5, 2, 2.5, -1, -0.666666666666667, -0.333333333333333, 0, 0.333333333333333, 0.666666666666667, 1, 1.33333333333333, 1.66666666666667, -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75, 1, 1.25, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1), .Dim = c(9L, 9L)));range(argv[[1]][[1]],argv[[1]][[2]], na.rm = TRUE);");
     }
+
+    // Following tests run range with the same input, but once with na.rm=F (default), na.rm=T and
+    // finite=T
+    private static final String[][] OPTIONAL_ARGS = new String[][]{{"", ", na.rm=T", ", finite=T"}};
+
+    @Test
+    public void testNaRmAndFiniteWithDoubles() {
+        assertEval(template("range(c(1.615, 3.19, 2.62, 3.44, NA, NA, 1.513)%0)", OPTIONAL_ARGS));
+        assertEval(template("range(c(1.615, 3.19, 2.62, 3.44, NaN, 1.513)%0)", OPTIONAL_ARGS));
+        assertEval(template("range(c(1.615, 3.19, -Inf, 3.44, Inf, 1.513)%0)", OPTIONAL_ARGS));
+    }
+
+    @Test
+    public void testNaRmAndFiniteWithIntegers() {
+        assertEval(template("range(c(2L, 3L, NA, NA, 1L)%0)", OPTIONAL_ARGS));
+    }
+
+    @Test
+    public void testNaRmAndFiniteWithLogical() {
+        assertEval(template("range(c(T, F, NA, NA, T)%0)", OPTIONAL_ARGS));
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java
index a5a22ee9a4fa24832793a1a1f04360e718572afe..558032e94439942a684f70b658f4e5392f6cc237 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rbind.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -76,5 +76,81 @@ public class TestBuiltin_rbind extends TestBase {
         assertEval("rbind(character(0), 'f')");
         assertEval("rbind(55, character(0))");
         assertEval("rbind(a=55, character(0))");
+
+        assertEval("v <- 1; attr(v, 'a') <- 'a'; rbind(v); rbind(v, v)");
+        assertEval("v <- 1; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; rbind(v); rbind(v, v)");
+        assertEval("v <- 1:3; attr(v, 'a') <- 'a'; attr(v, 'a1') <- 'a1'; rbind(v); rbind(v, v)");
+        assertEval("v <- 1:3; v1<-1:3; attr(v, 'a') <- 'a'; attr(v1, 'a1') <- 'a1'; rbind(v, v1)");
+    }
+
+    @Test
+    public void testGenericDispatch() {
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(...) 'foo'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(...) 'foo'; v2 <- 1; class(v2) <- 'foo'; rbind(v2) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; assign('rbind.foo', function(x) {'foo'}, envir=.__S3MethodsTable__.); result <- rbind(v) ; rm('rbind.foo', envir=.__S3MethodsTable__.); result;}");
+
+        // segfault in gnur
+        assertEval(Ignored.ReferenceError, "{ v <- 1; class(v) <- 'foo'; rbind.foo <- length; rbind(v) }");
+
+        assertEval(Output.IgnoreErrorContext, "{ v <- 1; class(v) <- 'foo'; rbind.foo <- rawToBits; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind(v) }");
+        assertEval("{ v <- 1; rbind.foo <- function(...) 'foo'; rbind(v) }");
+
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(deparse.level, ...) 'foo'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(deparse.level, x) 'foo'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(deparse.level, x1, x2) 'foo'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(x0, deparse.level, x1, x2) 'foo'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(x0, x1, x2) 'foo'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- 'foo'; rbind.foo <- function(x) 'foo'; rbind(v) }");
+        assertEval(Ignored.WrongCaller, "{ v <- 1; class(v) <- 'foo'; rbind.foo <- function() 'foo'; rbind(v) }");
+
+        assertEval("{ v <- 1; class(v) <- c('foo1', 'foo2'); rbind.foo1 <- function(...) 'foo1'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- c('foo1', 'foo2'); rbind.foo2 <- function(...) 'foo2'; rbind(v) }");
+        assertEval("{ v <- 1; class(v) <- c('foo1', 'foo2'); rbind.foo1 <- function(...) 'foo1'; rbind.foo2 <- function(...) 'foo2'; rbind(v) }");
+
+        assertEval("{ v1 <- 1; class(v1) <- 'foo1'; rbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind.foo2 <- function(...) 'foo2'; rbind(v1, v2) }");
+        assertEval("{ v1 <- 1; class(v1) <- 'foo1'; rbind.foo1 <- function(...) 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind(v1, v2) }");
+        assertEval("{ v1 <- 1; class(v1) <- 'foo1'; v2 <- 2; class(v2) <- 'foo2'; rbind.foo2 <- function(...) 'foo2'; rbind(v1, v2) }");
+    }
+
+    @Test
+    public void testDimnames() {
+        assertEval("{ attributes(rbind(integer(0))) }");
+        assertEval("{ attributes(rbind(1L)) }");
+        assertEval("{ attributes(rbind(c(1L, 2L))) }");
+        assertEval("{ attributes(rbind(1L, 2L)) }");
+
+        assertEval("{ rbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L) }");
+        assertEval("{ rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L) }");
+        assertEval("{ rbind(structure(1:4, dim=c(2,2)), 1L) }");
+
+        assertEval("{ attributes(rbind(structure(1:4, dim=c(2,2), dimnames=list(c('y1', 'y2'), c('x1', 'x2'))), 1L)) }");
+        assertEval("{ attributes(rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), 1L)) }");
+        assertEval("{ attributes(rbind(structure(1:4, dim=c(2,2)), 1L)) }");
+
+        assertEval("{ rbind(NULL, integer(0)) }");
+        assertEval("{ rbind(integer(0), integer(0)) }");
+        assertEval("{ rbind(c(1), integer(0)) }");
+        assertEval("{ rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0)) }");
+
+        assertEval("{ attributes(rbind(NULL, integer(0))) }");
+        assertEval("{ attributes(rbind(integer(0), integer(0))) }");
+        assertEval("{ attributes(rbind(c(1), integer(0))) }");
+        assertEval("{ attributes(rbind(structure(1:4, dim=c(2,2), dimnames=list(y=c('y1', 'y2'), x=c('x1', 'x2'))), integer(0))) }");
+    }
+
+    @Test
+    public void testRetType() {
+        assertEval("dput(rbind(NULL))");
+        assertEval("dput(rbind(NULL, integer(0)))");
+        assertEval("dput(rbind(NULL, NULL, integer(0)))");
+        assertEval("dput(rbind(NULL, NULL, double(0)))");
+        assertEval("dput(rbind(NULL, NULL, integer(0), double(0)))");
+        assertEval("dput(rbind(NULL, NULL, double(0), integer(0)))");
+        assertEval("dput(rbind(NULL, NULL, double(0), character(0)))");
+        assertEval("dput(rbind(NULL, NULL, double(0), integer(0), character(0)))");
+        assertEval("dput(rbind(c(NULL, NULL), integer(0)))");
+        assertEval("dput(rbind(integer(0)))");
+        assertEval("dput(rbind(integer(0), NULL, NULL))");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_along.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_along.java
index 8cdf55201a05931ff691cc70eb98464e25746128..afa9fbc4c185d0993242d34ba01b71b61c9e5945 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_along.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_along.java
@@ -141,7 +141,7 @@ public class TestBuiltin_seq_along extends TestBase {
         assertEval(Output.IgnoreWarningContext, "{ x <- c(1,2,3); class(x) <- 'myclass'; length.myclass <- function(w) 'hello world'; seq_along(x) }");
         // length defined in global env should not get us confused:
         assertEval("{ length <- function(x) 42; seq_along(c(1,2,3)) }");
-        // length in __S3MethodsTable__ should work too, N.B.: needs complete S3 dispatch support
-        assertEval(Ignored.Unimplemented, "{ assign('length.myclass', function(...) 42, envir=.__S3MethodsTable__.); x <- 1; class(x) <- 'myclass'; seq_along(x); }");
+        // length in __S3MethodsTable__ should work too
+        assertEval("{ assign('length.myclass', function(...) 42, envir=.__S3MethodsTable__.); x <- 1; class(x) <- 'myclass'; res <- seq_along(x); rm('length.myclass', envir=.__S3MethodsTable__.); res }");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java
index d48f6c25f09d12b5d23eb290dfc1bf7642aafe83..024362fa915abf7ec5eacfd11ca15285a7b33bf5 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java
@@ -55,7 +55,7 @@ public class TestBuiltin_sprintf extends TestBase {
 
     @Test
     public void testsprintf8() {
-        assertEval(Ignored.Unknown, "argv <- list('plot_%02g', 1L); .Internal(sprintf(argv[[1]], argv[[2]]))");
+        assertEval("argv <- list('plot_%02g', 1L); .Internal(sprintf(argv[[1]], argv[[2]]))");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substitute.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substitute.java
index 871968ec0b811ebe9dffe454d5791e2022bde4bf..ad2e9940d396e8865d77cb87da8e0c412f93eee5 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substitute.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substitute.java
@@ -87,5 +87,30 @@ public class TestBuiltin_substitute extends TestBase {
         assertEval("f<-function(x,name) substitute(x$name <- 5); f(foo, bar); foo <- new.env(); eval(f(foo,bar)); foo$bar");
         assertEval("f<-function(x,name) substitute(x@name); f(foo, bar); setClass('cl', representation(bar='numeric')); foo <- new('cl'); foo@bar <- 1; eval(f(foo,bar))");
         assertEval("f<-function(x,name) substitute(x@name <- 5); f(foo, bar); setClass('cl', representation(bar='numeric')); foo <- new('cl'); eval(f(foo,bar)); foo@bar");
+
+        assertEval("substitute(1, 1)");
+        assertEval("substitute(1, 1, 1)");
+        assertEval("substitute(expr=1, env=1)");
+
+        assertEval("substitute(1, NULL)");
+        assertEval("substitute(1, NA)");
+        assertEval("substitute(1, c(list(1)))");
+        assertEval("substitute(1, list(c(list(1))))");
+        assertEval("substitute(1, list(list(1)))");
+
+        assertEval("a<-substitute(quote(x+1), NULL); a");
+        assertEval("a<-substitute(quote(x+1), NA); a");
+        assertEval("a<-substitute(quote(x+1), list(1)); a");
+        assertEval("a<-substitute(quote(x+1), list(x=1)); a");
+        assertEval("a<-substitute(quote(x+1), list(y=1)); a");
+        assertEval("a<-substitute(quote(x+1), c(list(x=1), 'breakme')); a");
+        assertEval("a<-substitute(quote(x+1), c(c(list(x=1)))); a");
+        assertEval("a<-substitute(quote(x+1), list(c(c(list(x=1))))); a");
+        assertEval("a<-substitute(quote(x+1), list(list(x=1))); a");
+        assertEval("a<-substitute(quote(x+1), c(list(x=1, 1))); a");
+        assertEval("a<-substitute(quote(x+y), c(list(x=1), list(y=1))); a");
+        assertEval("substitute(quote(x+1), environment())");
+        assertEval("f<-function() {}; substitute(quote(x+1), f)");
+        assertEval("substitute(quote(x+1), setClass('a'))");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unclass.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unclass.java
index 7dd8dbaa17e66d79719e805bcd25e3842af19f36..6e9d92e306be8a904207a20fbe5f905ffb6d8f37 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unclass.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unclass.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -155,7 +155,7 @@ public class TestBuiltin_unclass extends TestBase {
 
     @Test
     public void testunclass27() {
-        assertEval("argv <- list(list(structure(list(label = 'FALSE', x = structure(0, unit = 'npc', valid.unit = 0L, class = 'unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'unit'), just = c('left', 'centre'), hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = 'GRID.text.106', gp = structure(list(), class = 'gpar'), vp = NULL), .Names = c('label', 'x', 'y', 'just', 'hjust', 'vjust', 'rot', 'check.overlap', 'name', 'gp', 'vp'), class = c('text', 'grob', 'gDesc'))));unclass(argv[[1]]);");
+        assertEval("argv <- list(list(structure(list(label = 'FALSE', x = structure(0, unit = 'npc', valid.unit = 0L, class = 'r_unit'), y = structure(0.5, unit = 'npc', valid.unit = 0L, class = 'r_unit'), just = c('left', 'centre'), hjust = NULL, vjust = NULL, rot = 0, check.overlap = FALSE, name = 'GRID.text.106', gp = structure(list(), class = 'r_gpar'), vp = NULL), .Names = c('label', 'x', 'y', 'just', 'hjust', 'vjust', 'rot', 'check.overlap', 'name', 'gp', 'vp'), class = c('r_text', 'r_grob', 'r_gDesc'))));unclass(argv[[1]]);");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java
index d3cd786a1aac0d087ab49eaae5efb38f7f1912f9..f1e24b620f01bfd682221f68b6cb7407f5ccac30 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -235,6 +235,11 @@ public class TestFunctions extends TestBase {
         // with ... partial-match only if formal parameter are before ...
         assertEval("{ f<-function(..., val=1) { c(list(...), val) }; f(v=7, 2) }");
         assertEval("{ f<-function(er=1, ..., val=1) { c(list(...), val, er) }; f(v=7, 2, e=8) }");
+
+        // exact match of 'xa' is not "stolen" by partial match of 'x'
+        assertEval("{ foo <- function(xa, ...) list(xa=xa, ...); foo(x=4,xa=5); }");
+        // however, two partial matches produce error, even if one is "longer"
+        assertEval("{ foo <- function(xaaa, ...) list(xaa=xaaa, ...); foo(xa=4,xaa=5); }");
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
index bc847b5fab907eefbb96f4edb503053990199b97..2c8c4652b6eb1dbf082f1eb985e0e62b2237d67c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
@@ -138,8 +138,8 @@ public class TestS3Dispatch extends TestRBase {
     public void testGenericDispatchThroughMethodsTable() {
         // Note: `[.term` is "private" in stats, but it has entry in __S3MethodsTable__
         assertEval("terms(x~z)[1];");
-        assertEval("{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x+x; }");
-        assertEval("{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x[[99]]; }");
+        assertEval("{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; res <- x+x; rm('Ops.myclass', envir=.__S3MethodsTable__.); res; }");
+        assertEval("{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; res <- x[[99]]; rm('[[.myclass', envir=.__S3MethodsTable__.); res; }");
     }
 
     @Override
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
index cbc3b17563ffd31b4c45dc886852c5b05d273ad0..eec8974833cac7fa384d397106682b90355d237b 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.debug.SuspendedCallback;
 import com.oracle.truffle.api.debug.SuspendedEvent;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.vm.PolyglotEngine;
+import com.oracle.truffle.r.runtime.ExitException;
 import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RError;
@@ -156,7 +157,7 @@ public final class FastRSession implements RSession {
     }
 
     public ContextInfo createContextInfo(ContextKind contextKind) {
-        RStartParams params = new RStartParams(RCmdOptions.parseArguments(Client.RSCRIPT, new String[0], false), false);
+        RStartParams params = new RStartParams(RCmdOptions.parseArguments(Client.RSCRIPT, new String[]{"--no-restore"}, false), false);
         return ContextInfo.create(params, null, contextKind, mainContext, consoleHandler, TimeZone.getTimeZone("GMT"));
     }
 
@@ -182,17 +183,6 @@ public final class FastRSession implements RSession {
 
     @Override
     public String eval(TestBase testClass, String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable {
-        evalAsObject(testClass, expression, contextInfo, longTimeout);
-        return consoleHandler.buffer.toString();
-    }
-
-    /**
-     * Returns the actual object from evaluating expression. Used (and result ignored) by
-     * {@link #eval} but also used for package installation via the {@code system2} command, where
-     * the result is used to check whether the installation succeeded.
-     */
-    public Object evalAsObject(TestBase testClass, String expression, ContextInfo contextInfo, boolean longTimeout) throws Throwable {
-        Object result = null;
         Timer timer = null;
         consoleHandler.reset();
         try {
@@ -211,7 +201,7 @@ public final class FastRSession implements RSession {
                     Source source = RSource.fromTextInternal(input, RSource.Internal.UNIT_TEST);
                     try {
                         try {
-                            result = vm.eval(source).get();
+                            vm.eval(source);
                             // checked exceptions are wrapped in RuntimeExceptions
                         } catch (RuntimeException e) {
                             if (e.getCause() instanceof com.oracle.truffle.api.vm.IncompleteSourceException) {
@@ -234,6 +224,8 @@ public final class FastRSession implements RSession {
             }
         } catch (ParseException e) {
             e.report(consoleHandler);
+        } catch (ExitException e) {
+            // exit exceptions are legitimate if a test case calls "q()"
         } catch (RError e) {
             // nothing to do
         } catch (Throwable t) {
@@ -249,7 +241,7 @@ public final class FastRSession implements RSession {
                 timer.cancel();
             }
         }
-        return result;
+        return consoleHandler.buffer.toString();
     }
 
     private static Timer scheduleTimeBoxing(PolyglotEngine engine, long timeout) {
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
index 3601a1216d95331d537b24c89cb3a1132a7c0d4f..5771c2814c844a5c8bc20b1fcc0a35393c59b397 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/GnuROneShotRSession.java
@@ -46,7 +46,7 @@ import com.oracle.truffle.r.test.TestBase;
  */
 public class GnuROneShotRSession implements RSession {
 
-    private static final String[] GNUR_COMMANDLINE = new String[]{"<R>", "--vanilla", "--slave", "--silent"};
+    private static final String[] GNUR_COMMANDLINE = new String[]{"<R>", "--vanilla", "--slave", "--silent", "--no-restore"};
     private static final String FASTR_TESTGEN_GNUR = "FASTR_TESTGEN_GNUR";
     private static final String NATIVE_PROJECT = "com.oracle.truffle.r.native";
     private static final int DEFAULT_TIMEOUT_MINS = 5;
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java
index da01131596867aa995cec32575a0fe560592ad15..1bfcae0799319dfb90ad71c300d5919b36e177d8 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/TestOutputManager.java
@@ -40,6 +40,7 @@ import java.util.SortedMap;
 import java.util.TreeMap;
 
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.test.TestBase;
 import com.oracle.truffle.r.test.TestBase.Context;
 import com.oracle.truffle.r.test.TestBase.Ignored;
 import com.oracle.truffle.r.test.TestBase.Output;
@@ -401,7 +402,7 @@ public class TestOutputManager {
      * @param keepTrailingWhiteSpace if {@code true} preserve trailing white space, otherwise trim
      * @return the GnuR output
      */
-    public String genTestResult(String testElementName, String test, DiagnosticHandler d, boolean checkOnly, boolean keepTrailingWhiteSpace, TestTrait... traits) {
+    public String genTestResult(TestBase testClass, String testElementName, String test, DiagnosticHandler d, boolean checkOnly, boolean keepTrailingWhiteSpace, TestTrait... traits) {
         Map<String, TestInfo> testMap = getTestMap(testElementName);
         TestInfo testInfo = testMap.get(test);
         if (testInfo != null) {
@@ -418,7 +419,8 @@ public class TestOutputManager {
             String expected = null;
             if (!checkOnly) {
                 try {
-                    expected = rSession.eval(null, test, null, false);
+                    testClass.beforeEval();
+                    expected = rSession.eval(testClass, test, null, false);
                 } catch (Throwable e) {
                     throw RInternalError.shouldNotReachHere("unexpected exception thrown by GNUR session: " + e);
                 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java
index 2aff030fb231737e9ef235ccda7fe76c4f3a44f8..8d7b2dcf1abc33ede8b98aa6ddc300275d0c5df2 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestConditionHandling.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,9 +24,14 @@ package com.oracle.truffle.r.test.library.base;
 
 import org.junit.Test;
 
-import com.oracle.truffle.r.test.TestBase;
+import com.oracle.truffle.r.test.TestRBase;
 
-public class TestConditionHandling extends TestBase {
+public class TestConditionHandling extends TestRBase {
+
+    @Override
+    public String getTestDir() {
+        return "library/base/condition";
+    }
 
     @Test
     public void testTryCatch() {
@@ -38,5 +43,25 @@ public class TestConditionHandling extends TestBase {
         assertEval(Ignored.Unknown, "{ tryCatch(stop(\"fred\"), error = function(e) e, finally = print(\"Hello\"))}");
         assertEval("{ f <- function() { tryCatch(1, error = function(e) print(\"Hello\")); stop(\"fred\")}; f() }");
         assertEval("{ f <- function() { tryCatch(stop(\"fred\"), error = function(e) print(\"Hello\"))}; f() }");
+        assertEval("{ tryCatch(stop(\"xyz\"), error=function(e) { cat(\"<error>\");123L }, finally=function() { cat(\"<finally>\")}) }");
+    }
+
+    @Test
+    public void testWithRestarts() {
+        assertEval("withRestarts({cat(\"<start>\");invokeRestart(\"foo\", 123L, 456L);789L},\n foo=function(a,b) c(a,b))");
+        assertEval("withRestarts({cat(\"<start>\");invokeRestart(\"foo\", 123L, 456L);789L},\n foo=list(description=\"my handler\", handler=function(a,b) c(a,b)))");
+        assertEval("withRestarts({cat(\"<start>\");invokeRestart(\"foo\", 123L, 456L);789L},\n foo=function(a,b) {cat(\"<first>\");invokeRestart(\"foo\", a+1, b+1)},\n foo=function(a,b) {cat(\"<second>\");c(a,b)})");
+        assertEval("withRestarts(findRestart(\"noSuchRestart\"),\n foo=function(a,b) c(a,b))");
+        assertEval("withRestarts(findRestart(\"foo\"),\n foo=function(a,b) c(a,b))");
+        assertEval("withRestarts(computeRestarts(),\n foo=function(a,b) c(a,b))");
+    }
+
+    @Test
+    public void testWithCallingHandlers() {
+        assertEval(Output.IgnoreWarningContext, "withCallingHandlers({warning(\"foo\");123L},\n warning=function(e) {cat(\"<warn>\")})");
+        assertEval(Ignored.ImplementationError, "withCallingHandlers({warning(\"foo\");123L},\n warning=function(e) {\n cat(\"<warn>\")\n invokeRestart(\"muffleWarning\")\n })");
+        assertEval("withCallingHandlers({message(\"foo\");123L},\n message=function(e) {cat(\"<msg>\")})");
+        assertEval("withCallingHandlers({message(\"foo\");123L},\n message=function(e) {\n cat(\"<msg>\")\n invokeRestart(\"muffleMessage\")\n })");
+        assertEval("withCallingHandlers({message(\"foo\");packageStartupMessage(\"bar\");123L},\n packageStartupMessage=function(e) {\n cat(\"<msg>\")\n invokeRestart(\"muffleMessage\")\n })");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleLists.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleLists.java
index cfcffb27f3dbbe436ce32644f678d54bc4fb0885..d0add2169743d95cfebce812ad9a3e8811a81da6 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleLists.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleLists.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -150,4 +150,15 @@ public class TestSimpleLists extends TestBase {
         assertEval("l <- list(); l$x <- c(NA); length(l$x) <- 10; l$x[1] <- 42; invisible(tracemem(l$x)); l$x[2:9] <- 42;");
         assertEval("x <- list(c(1,2,3)); invisible(tracemem(x)); x[[1]] <- 42;");
     }
+
+    @Test
+    public void testNullListAssignment() {
+        assertEval("a<-NULL; a$b<-42L; dput(a)");
+        assertEval("a<-NULL; a$b<-print; dput(a)");
+        assertEval("a<- NULL; a <- `$<-`(a, \"a\", 1); dput(a)");
+        assertEval("a<- NULL; a <- `[[<-`(a, \"a\", 1); dput(a)");
+        assertEval("a<- NULL; a <- `[[<-`(a, 1, 1); dput(a)");
+        assertEval("a<- NULL; a <- `$<-`(a, 1, 1); dput(a)");
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers0.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers0.R
new file mode 100644
index 0000000000000000000000000000000000000000..85acd59a6af3d527c70000c57430fa4fdf38a0e7
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers0.R
@@ -0,0 +1,33 @@
+# Ignored
+myCondition <- function(message) structure(list(message=message, call=NULL), class=c("myCondition", "condition"))
+
+handle_myCondition <- function(e) {
+  print(paste("enter handle_myCondition", e))
+  invokeRestart("continue_test")
+  print("after restart")
+}
+
+fun0 <- function(code) {
+      withCallingHandlers({
+      print(code)
+      eval(code)
+      },
+      myCondition = handle_myCondition
+    ); 
+    print("exit fun0") 
+}
+
+fun1 <- function(s) {
+	print(paste("enter fun1", s))
+	withRestarts(
+		{ signalCondition(myCondition(paste0("signal", s))); print("afterSignal") } ,
+		continue_test = function(e) print("continue")
+	)
+	print(paste("exit fun1", s))
+	NULL
+}
+
+fun0({
+	fun1("first")
+	fun1("second")
+})
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers1.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers1.R
new file mode 100644
index 0000000000000000000000000000000000000000..0345697134cae2a5c8b2e6513b4e799d20987530
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/condition/R/withCallingHandlers1.R
@@ -0,0 +1,45 @@
+# Ignored
+cond0 <- function(message)
+  structure(list(message=message, call=NULL), class=c("cond0", "condition"))
+
+cond1 <- function(message)
+  structure(list(message=message, call=NULL), class=c("cond1", "condition"))
+
+handle_cond0 <- function(e) {
+  print(paste("enter handle_cond0", e))
+  invokeRestart("continue_test")
+  print("after cond0 restart")
+}
+
+handle_cond1 <- function(e) {
+  print(paste("enter handle_cond1", e))
+  signalCondition(e)
+  print("after cond1 restart")
+}
+
+fun0 <- function(code) {
+      withCallingHandlers({
+      print(code)
+      eval(code)
+      },
+      cond0 = handle_cond0,
+      cond1 = handle_cond1
+    ); 
+    print("exit fun0") 
+}
+
+fun1 <- function(s) {
+	print(paste("enter fun1", s))
+	withRestarts(
+		{ signalCondition(cond1(paste0("signal", s)));signalCondition(cond0(paste0("signal", s))); print("afterSignal") } ,
+		continue_test = function(e) print("continue")
+	)
+	print(paste("exit fun1", s))
+	NULL
+}
+
+fun0({
+	fun1("first")
+	fun1("second")
+})
+
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/grid/TestGridPackage.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/grid/TestGridPackage.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0e5c6639a997fd10288cd9b02b526a7922412b3
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/grid/TestGridPackage.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.library.grid;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+/**
+ * Tests non-graphical functions in grid package.
+ */
+public class TestGridPackage extends TestBase {
+    @Test
+    public void testUnits() {
+        run("unit.c(unit(1,'mm'), unit(1,'mm'))");
+        run("3 * (unit(1, 'mm'));");
+        run("grid:::unit.list(3 * unit(1, 'mm'));");
+        run("unit.c(unit(1,'mm'), 42*unit(1,'mm'));");
+    }
+
+    private void run(String testCode) {
+        assertEval(String.format("{ library(grid); %s }", testCode));
+    }
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/methods/TestSubstituteDirect.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/methods/TestSubstituteDirect.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ab7f98157a5087cf473adfec54580e8095dfe32
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/methods/TestSubstituteDirect.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.library.methods;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+public class TestSubstituteDirect extends TestBase {
+
+    @Test
+    public void basicTests() {
+        assertEval("substituteDirect(NULL, list(x=1))");
+        assertEval("substituteDirect(NA, list(x=1))");
+        assertEval("substituteDirect(environment(), list(x=1))");
+        assertEval("substituteDirect(1, 1)");
+        assertEval("substituteDirect(1, 1, 1)");
+        assertEval("substituteDirect(object=1, frame=1)");
+        assertEval("substituteDirect(object=1, frame=1, cleanFunction=1)");
+
+        assertEval("substituteDirect(1, frame=NULL)");
+        assertEval("substituteDirect(1, frame=NA)");
+        assertEval("substituteDirect(object=1, frame=c(list(1)))");
+        assertEval("substituteDirect(object=1, frame=list(c(list(1))))");
+        assertEval("substituteDirect(object=1, frame=list(list(1)))");
+
+        assertEval("a<-substituteDirect(quote(x+1), NULL); a");
+        assertEval("a<-substituteDirect(quote(x+1), NA); a");
+        assertEval("a<-substituteDirect(quote(x+1), list(1)); a");
+        assertEval("a<-substituteDirect(quote(x+1), list(x=1)); a");
+        assertEval("a<-substituteDirect(quote(x+1), list(y=1)); a");
+        assertEval("a<-substituteDirect(quote(x+1), c(list(x=1), 'breakme')); a");
+        assertEval("a<-substituteDirect(quote(x+1), c(c(list(x=1)))); a");
+        assertEval("a<-substituteDirect(quote(x+1), list(c(c(list(x=1))))); a");
+        assertEval("a<-substituteDirect(quote(x+1), list(list(x=1))); a");
+        assertEval("a<-substituteDirect(quote(x+1), c(list(x=1, 1))); a");
+        assertEval("a<-substituteDirect(quote(x+y), c(list(x=1), list(y=1))); a");
+        assertEval("substituteDirect(quote(x+1), frame=environment())");
+        assertEval("f<-function() {}; substituteDirect(quote(x+1), frame=f)");
+        assertEval("substituteDirect(quote(x+1), frame=setClass('a'))");
+
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=TRUE)");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=c(TRUE, 'breakme'))");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=c(c(TRUE, 'breakme')))");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=c(TRUE, FALSE))");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=list(c(TRUE), 'breakme'))");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=NA)");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=NULL)");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction='a')");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=c('1'))");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=c(1))");
+        assertEval("substituteDirect(quote(x+1), list(x=1), cleanFunction=environment())");
+    }
+
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java
index deb60b64d75a815886b0db2f360e6c4c3489d4c1..c2d7be4e0b73e889737f4a424536c3a14a7ba03e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,8 @@ public class TestFormulae extends TestBase {
     private static final String[] FORMULAE = new String[]{
                     "y~z", "y~1+z", "y~0+z", "y~-1+z", "y~z*k", "y~z*k+w*m", "u~z*k+w*m",
                     "y~z:k", "y~z^2", "y~(z+k)^2", "y~z*((m+w)^3)",
-                    "y~(z+k)*(w+u)", "y~w%in%v", "y~w/k", "y~(1 + w/k)"
+                    "y~(z+k)*(w+u)", "y~w%in%v", "y~w/k", "y~(1 + w/k)",
+                    "~k+y+z"
     };
 
     /**
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestSplineFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestSplineFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..defaaa8812de51da17c89a5eda3e7778328c7f41
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestSplineFunctions.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.library.stats;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+public class TestSplineFunctions extends TestBase {
+
+    @Test
+    public void basicSplineCoef() {
+        // method "periodic"
+        assertEval(".Call(stats:::C_SplineCoef, 1, c(1), c(1))");
+        assertEval(".Call(stats:::C_SplineCoef, 1, c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, 1, c(1:6), c(1:5, 1))");
+        // method "natural"
+        assertEval(".Call(stats:::C_SplineCoef, 2, c(1), c(1))");
+        assertEval(".Call(stats:::C_SplineCoef, 2, c(1:5), c(1:5))");
+        // method "fmm"
+        assertEval(".Call(stats:::C_SplineCoef, 3, c(1:5), c(1:5))");
+        // method "hyman"
+        assertEval(".Call(stats:::C_SplineCoef, 4, c(1:5), c(1:5))");
+
+        assertEval(".Call(stats:::C_SplineCoef, 0, c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, -1, c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, 111, c(1:5), c(1:5))");
+
+        assertEval(".Call(stats:::C_SplineCoef, NULL, c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, NA, c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, c(), c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, list(), c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, c(list()), c(1:5), c(1:5))");
+        assertEval(Ignored.WrongCaller, ".Call(stats:::C_SplineCoef, 'abc', c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, c(1), c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, c(1, 2, 3), c(1), c(1))");
+        assertEval(Ignored.WrongCaller, ".Call(stats:::C_SplineCoef, c('a'), c(1), c(1))");
+        assertEval(Ignored.WrongCaller, ".Call(stats:::C_SplineCoef, list(1), c(1), c(1))");
+        assertEval(Ignored.WrongCaller, ".Call(stats:::C_SplineCoef, environment(), c(1:5), c(1:5))");
+        assertEval(Ignored.WrongCaller, ".Call(stats:::C_SplineCoef, function() {}, c(1:5), c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, 1, list(1), c(1))");
+        assertEval(".Call(stats:::C_SplineCoef, 1, c(1), list(1))");
+
+        assertEval(".Call(stats:::C_SplineCoef, 1, NULL, c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, 1, NA, c(1:5))");
+        assertEval(".Call(stats:::C_SplineCoef, 1, c(1:5), NULL)");
+        assertEval(".Call(stats:::C_SplineCoef, 1, c(1:5), NA)");
+        assertEval(".Call(stats:::C_SplineCoef, 1, NULL, NULL)");
+        assertEval(".Call(stats:::C_SplineCoef, 1, NA, NA)");
+    }
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/modelTests.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/modelTests.R
index d4458943fbd3bca915de0cec2cdb928819cd8a22..583810e2628389de07f020badfa4dd4ad6d7366c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/modelTests.R
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/modelTests.R
@@ -1,4 +1,4 @@
-# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,7 @@ check <- function(expected, actual, name) {
 # tests data: formulae
 tests <- c(y~z, y~1+z, y~0+z, y~-1+z, y~z*k, y~z*k+w*m, u~z*k+w*m, y~z:k)
 tests <- c(tests, y~z^2, y~(z+k)^2, y~z*((m+w)^3), y~(z+k)*(w+u))
-tests <- c(tests, y~w%in%v, y~w/k, y~(1 + w/k))
+tests <- c(tests, y~w%in%v, y~w/k, y~(1 + w/k), ~k+y+z)
 ignoremm <- c(y~log(z), y~z+I(k+4), y~z+I(k^2), y~z+offset(log(z)))
 ignoremf <- NULL
 tests <- c(tests, ignoremm)
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestTypeConvert.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestTypeConvert.java
index 972ac0da24429ada9a1df550e8466f806b13cf2b..2096f7059b4ef0e12eea62f1a015cfda8ef4bb88 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestTypeConvert.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestTypeConvert.java
@@ -58,4 +58,41 @@ public class TestTypeConvert extends TestBase {
         // UnsupportedSpecializationException: Unexpected values provided for ...
         assertEval(Ignored.Unimplemented, "type.convert('NA', 1)");
     }
+
+    @Test
+    public void typeConvertExternal2Test() {
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', NA, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', NULL, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', 'TRUE', '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', 'abc', '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', list('abc'), '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', list(), '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', c(), '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', c(NULL), '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', 1, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', 2, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', environment(), '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), 'NA', function() {}, '.', 'allow.loss')");
+
+        assertEval(".External2(utils:::C_typeconvert, NULL, 'NA', FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, NA, 'NA', FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c(), 'NA', FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), NULL, FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), NA, FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), c(), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c(1), c(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c(1, TRUE), c(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c(1, 'TRUE'), c(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c(1, 'TRUE', 'x'), c(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c(1, '1'), c(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c(1, 'x'), c(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), c(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, list(1), list(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, list('1'), list('1'), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, list('1'), list(1), FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, environment(), 'NA', FALSE, '.', 'allow.loss')");
+        assertEval(".External2(utils:::C_typeconvert, c('1'), environment(), FALSE, '.', 'allow.loss')");
+    }
+
 }
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 400a9c7b8f90f0a833c0fa568b46212095152d8c..58fc5690fd0f93b2ae38869dcdea351fc5ad632c 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.oracle.truffle.r.test.TestBase;
+import com.oracle.truffle.r.test.TestTrait;
 import com.oracle.truffle.r.test.rpackages.TestRPackages;
 
 public class TestRFFIPackage extends TestRPackages {
@@ -40,7 +41,7 @@ public class TestRFFIPackage extends TestRPackages {
 
     @AfterClass
     public static void tearDownUninstallMyTestPackages() {
-        tearDownUninstallTestPackages(TEST_PACKAGES);
+        tearDownUninstallTestPackages();
     }
 
     /**
@@ -48,12 +49,22 @@ public class TestRFFIPackage extends TestRPackages {
      * 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\", unload=T); x }", new String[]{TestRPackages.libLoc()}));
+    private void assertEvalWithLibWithSetupAndTrait(TestTrait trait, String setup, String test) {
+        String[] tests = TestBase.template("{ library(\"testrffi\", lib.loc = \"%0\"); " + setup + "x <- " + test + "; detach(\"package:testrffi\", unload=T); x }",
+                        new String[]{TestRPackages.libLoc()});
+        if (trait == null) {
+            assertEval(tests);
+        } else {
+            assertEval(trait, tests);
+        }
     }
 
     private void assertEvalWithLib(String test) {
-        assertEvalWithLibWithSetup("", test);
+        assertEvalWithLibWithSetupAndTrait(null, "", test);
+    }
+
+    private void assertEvalWithLibWithSetup(String setup, String test) {
+        assertEvalWithLibWithSetupAndTrait(null, setup, test);
     }
 
     @Test
@@ -165,4 +176,44 @@ public class TestRFFIPackage extends TestRPackages {
     public void testRFFI20() {
         assertEvalWithLibWithSetup("x <- \"12345\"; ", "rffi.char_length(x)");
     }
+
+    private static final String[] AS_VALUES = new String[]{"1L", "2", "2.2", "T", "integer()", "numeric()", "logical()", "character()", "c(5,6)", "c(2.3, 3.4)", "c(T, F)",
+                    "as.symbol(\"sym\")", "list()"};
+
+    private static final String[] AS_FUNS = new String[]{"Char", "Integer", "Real", "Logical"};
+
+    @Test
+    public void testAsFunctions() {
+        String[] asCalls = template("x <- append(x, rffi.as%0(%1)); ", AS_FUNS, AS_VALUES);
+        assertEvalWithLibWithSetupAndTrait(Output.MayIgnoreWarningContext, "x <- list(); ", flatten(asCalls));
+    }
+
+    private static final String[] LIST_FUNS = new String[]{"CAR", "CDR"};
+
+    private static final String[] LIST_VALUES = new String[]{"pairlist(1,2)", "pairlist(x=1L, y=2L)"};
+
+    @Test
+    public void testListFunctions() {
+        String[] calls = template("x <- append(x, rffi.%0(%1)); ", LIST_FUNS, LIST_VALUES);
+        assertEvalWithLibWithSetupAndTrait(Output.MayIgnoreErrorContext, "x <- list(); ", flatten(calls));
+
+    }
+
+    private static String flatten(String[] tests) {
+        StringBuilder sb = new StringBuilder();
+        for (String test : tests) {
+            sb.append(test);
+        }
+        return sb.toString();
+    }
+
+    private static final String[] LENGTH_VALUES = new String[]{"1", "c(1,2,3)", "list(1,2,3)", "expression(1,2)"};
+
+    // Checkstyle: stop method name check
+    @Test
+    public void TestLENGTH() {
+        String[] calls = template("x <- append(x, rffi.LENGTH(%0)); ", LENGTH_VALUES);
+        assertEvalWithLibWithSetupAndTrait(Output.MayIgnoreErrorContext, "x <- list(); ", flatten(calls));
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestRFFIPackageCoercions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestRFFIPackageCoercions.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bff0cf831b4f59dbd62acecb6dbf88ab4c820fc
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rffi/TestRFFIPackageCoercions.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.rffi;
+
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.CPLXSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.EXPRSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.INTSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.LGLSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.NILSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.RAWSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.REALSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.STRSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.SYMSXP;
+import static com.oracle.truffle.r.runtime.gnur.SEXPTYPE.VECSXP;
+
+import java.util.Arrays;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
+import com.oracle.truffle.r.test.rpackages.TestRPackages;
+
+public class TestRFFIPackageCoercions extends TestRPackages {
+
+    private static final String[] TEST_PACKAGES = new String[]{"testrffi"};
+
+    @BeforeClass
+    public static void setupInstallMyTestPackages() {
+        setupInstallTestPackages(TEST_PACKAGES);
+    }
+
+    @AfterClass
+    public static void tearDownUninstallMyTestPackages() {
+        tearDownUninstallTestPackages();
+    }
+
+    private String addLib(String test) {
+        return "{ library('testrffi', lib.loc = '" + TestRPackages.libLoc() + "'); x <- " + test + "; detach('package:testrffi', unload=T); x }";
+    }
+
+    private static final String[] COERCION_VALUES_FOR_EXPR = new String[]{
+                    "2", "2.2", "T", "integer()", "numeric()", "logical()", "character()", "c(5,6)", "c(2.3, 3.4)", "c(T, F)",
+                    "list()", "structure(2.2, names='b',dim=c(1,1),myattr='q')", "structure(T, names='c',dim=c(1,1),myattr='q')"};
+
+    private static final String[] COERCION_VALUES = new String[]{
+                    "1L", "2", "2.2", "T", "integer()", "numeric()", "logical()", "character()", "c(5,6)", "c(2.3, 3.4)",
+                    "c(T, F)", "list()", "structure(1L,names='a',dim=c(1,1),myattr='q')", "structure(2.2, names='b',dim=c(1,1),myattr='q')",
+                    "structure(T, names='c',dim=c(1,1),myattr='q')", "structure(list(1,'42'), names=c('q','w'),dim=c(2,1),myattr='q')"};
+
+    private static final SEXPTYPE[] COERCION_TYPES = new SEXPTYPE[]{SYMSXP, NILSXP, VECSXP, INTSXP, REALSXP, LGLSXP, STRSXP, CPLXSXP, RAWSXP};
+
+    private static final String[] COERCION_MODES = Arrays.stream(COERCION_TYPES).map(x -> Integer.toString(x.code)).toArray(n -> new String[n]);
+
+    @Test
+    public void testCoerceVector() {
+        String[] tests = template(addLib("rffi.coerceVector(%0, %1)"), COERCION_VALUES, COERCION_MODES);
+        assertEval(Output.MayIgnoreWarningContext, Output.MayIgnoreErrorContext, tests);
+    }
+
+    @Test
+    public void testCoerceVectorToExpression() {
+        // Note: inconsistency when printing expression(1L) FastR prints just "expression(1)"
+        String[] tests = template(addLib("rffi.coerceVector(%0, %1)"), COERCION_VALUES_FOR_EXPR, new String[]{Integer.toString(EXPRSXP.code)});
+        assertEval(Output.IgnoreErrorMessage, Output.MayIgnoreWarningContext, Output.MayIgnoreErrorContext, tests);
+        // removes the attributes when its single value, but keeps them when it's a list
+        assertEval(Ignored.Unimplemented, addLib("rffi.coerceVector(structure(list(1,'x'), names=c('q','w'),dim=c(2,1),myattr='q'), " + EXPRSXP.code + ")"));
+    }
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java
index e25c359840854577f5b7270e2a7e2d44c68a29a6..40e4f8d269398f4b187a9d0983b319aa329d6bd0 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRPackages.java
@@ -31,7 +31,6 @@ import org.junit.Assert;
 
 import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RVersionNumber;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.test.TestBase;
 
 /**
@@ -59,6 +58,10 @@ public abstract class TestRPackages extends TestBase {
 
     private static final String SYSTEM2_COMMAND = "system2('%s', c('CMD', 'INSTALL', '%s'), env='R_LIBS=%s', stdout=T, stderr=T)";
 
+    private static String[] installedPackages;
+    private static Resolver resolver;
+    private static boolean needsInstall;
+
     private static final class PackagePath {
         /**
          * The path containing the package distributions as tar files.
@@ -124,10 +127,6 @@ public abstract class TestRPackages extends TestBase {
         return result;
     }
 
-    protected static void setupInstallTestPackages(String[] testPackages) {
-        setupInstallTestPackages(testPackages, new Resolver());
-    }
-
     private static boolean installPackage(PackagePath packagePath) {
         String cmd;
         Path binBase;
@@ -140,54 +139,68 @@ public abstract class TestRPackages extends TestBase {
         }
         cmd = binBase.resolve("bin").resolve("R").toString();
         try {
-            Object result = evalInstallPackage(String.format(SYSTEM2_COMMAND, cmd, packagePath.path.toString(), installDir().toString()));
-            boolean success;
-            if (generatingExpected()) {
-                String stringResult = (String) result;
-                success = stringResult.contains("* DONE (");
-                if (!success) {
-                    System.out.println(stringResult);
-                }
-            } else {
-                RStringVector vecResult = (RStringVector) result;
-                success = vecResult.getAttr("status") == null;
-                if (!success) {
-                    String[] output = vecResult.getDataWithoutCopying();
-                    for (String line : output) {
-                        System.out.println(line);
-                    }
-                }
+            String result = evalInstallPackage(String.format(SYSTEM2_COMMAND, cmd, packagePath.path.toString(), installDir().toString()));
+            boolean success = result.contains("* DONE (");
+            if (!success) {
+                System.out.println(result);
             }
             return success;
         } catch (Throwable t) {
+            t.printStackTrace();
             return false;
         }
     }
 
+    protected static void setupInstallTestPackages(String[] testPackages) {
+        setupInstallTestPackages(testPackages, new Resolver());
+    }
+
     protected static void setupInstallTestPackages(String[] testPackages, Resolver resolver) {
         if (!checkOnly()) {
+            assert installedPackages == null && TestRPackages.resolver == null : "inconsistent calls to setupInstallTestPackages / tearDownUninstallTestPackages " + installedPackages + " " + resolver;
+            TestRPackages.installedPackages = testPackages;
+            TestRPackages.resolver = resolver;
+            TestRPackages.needsInstall = true;
+        }
+    }
+
+    private boolean packagesInstallSuccess = true;
+
+    @Override
+    public void beforeEval() {
+        if (needsInstall) {
+            needsInstall = false;
+
             TestBase.deleteDir(installDir());
             installDir().toFile().mkdirs();
             System.out.printf(".begin install.");
-            for (String p : testPackages) {
+            for (String p : installedPackages) {
                 // Takes time, provide user feedback
                 System.out.printf(".pkg: %s.", p);
                 PackagePath packagePath = getPackagePaths(p, resolver.getPath(p));
                 if (!installPackage(packagePath)) {
+                    packagesInstallSuccess = false;
                     Assert.fail(String.format("package %s failed to install", p));
                 }
             }
             System.out.printf(".end install.");
         }
+        // This makes sure that any consequent tests fail with informative error
+        Assert.assertTrue("Error during package installation process.", packagesInstallSuccess);
     }
 
-    protected static void tearDownUninstallTestPackages(String[] testPackages) {
+    protected static void tearDownUninstallTestPackages() {
         if (!checkOnly()) {
-            for (String p : testPackages) {
-                if (!uninstallPackage(p)) {
-                    System.err.println("WARNING: error deleting package: " + p);
+            assert installedPackages != null && resolver != null : "inconsistent calls to setupInstallTestPackages / tearDownUninstallTestPackages";
+            if (!needsInstall) {
+                for (String p : installedPackages) {
+                    if (!uninstallPackage(p)) {
+                        System.err.println("WARNING: error deleting package: " + p);
+                    }
                 }
             }
+            installedPackages = null;
+            resolver = null;
         }
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRecommendedPackages.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRecommendedPackages.java
index 53d8d460ccb9cb1fe5e8635d63be7cf4eb1f1ce2..04ab1ce911c96d09bfd1a741d56a6625b3bd295f 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRecommendedPackages.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRecommendedPackages.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -78,7 +78,7 @@ public class TestRecommendedPackages extends TestRPackages {
 
     @AfterClass
     public static void tearDownUninstallMyTestPackages() {
-        tearDownUninstallTestPackages(packages);
+        tearDownUninstallTestPackages();
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestS4TestPackage.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestS4TestPackage.java
index ce2a48e598f43e587aa819f422e5eecaa44beb15..5843ad45da8f693c315df98ad880aaa92e348ad4 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestS4TestPackage.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestS4TestPackage.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@ public class TestS4TestPackage extends TestRPackages {
 
     @AfterClass
     public static void tearDownUninstallMyTestPackages() {
-        tearDownUninstallTestPackages(TEST_PACKAGES);
+        tearDownUninstallTestPackages();
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestVanillaPackage.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestVanillaPackage.java
index 7bd9ce16caef3b0c1edee6585f1dbd04d4e6f303..637377fa32eb74183e6864bb203e9d52eb699206 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestVanillaPackage.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestVanillaPackage.java
@@ -42,7 +42,7 @@ public class TestVanillaPackage extends TestRPackages {
 
     @AfterClass
     public static void tearDownUninstallMyTestPackages() {
-        tearDownUninstallTestPackages(TEST_PACKAGES);
+        tearDownUninstallTestPackages();
     }
 
     @Test
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
index d8a04e48887dd7d5328d1f2abc712dec20ded2b3..0016b0ebc3e6108885c8411d5277b69fa1d4109f 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,29 +30,37 @@ import static org.junit.Assert.assertTrue;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.oracle.truffle.api.debug.Breakpoint;
+import com.oracle.truffle.api.debug.DebugStackFrame;
+import com.oracle.truffle.api.debug.DebugValue;
 import com.oracle.truffle.api.debug.Debugger;
+import com.oracle.truffle.api.debug.DebuggerSession;
 import com.oracle.truffle.api.debug.SuspendedEvent;
-import com.oracle.truffle.api.frame.FrameSlot;
-import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.api.vm.PolyglotEngine.Value;
 import com.oracle.truffle.r.runtime.RSource;
+import com.oracle.truffle.r.runtime.RCmdOptions.Client;
+import com.oracle.truffle.r.runtime.context.ConsoleHandler;
+import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.DefaultConsoleHandler;
+import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.runtime.data.RPromise.EagerPromiseBase;
 
-@SuppressWarnings("deprecation")
 public class FastRDebugTest {
     private Debugger debugger;
+    private DebuggerSession debuggerSession;
     private final LinkedList<Runnable> run = new LinkedList<>();
     private SuspendedEvent suspendedEvent;
     private Throwable ex;
-    private com.oracle.truffle.api.debug.ExecutionEvent executionEvent;
     protected PolyglotEngine engine;
     protected final ByteArrayOutputStream out = new ByteArrayOutputStream();
     protected final ByteArrayOutputStream err = new ByteArrayOutputStream();
@@ -60,29 +68,23 @@ public class FastRDebugTest {
     @Before
     public void before() {
         suspendedEvent = null;
-        executionEvent = null;
-        engine = PolyglotEngine.newBuilder().setOut(out).setErr(err).onEvent(
-                        new com.oracle.truffle.api.vm.EventConsumer<com.oracle.truffle.api.debug.ExecutionEvent>(com.oracle.truffle.api.debug.ExecutionEvent.class) {
-                            @Override
-                            protected void on(com.oracle.truffle.api.debug.ExecutionEvent event) {
-                                executionEvent = event;
-                                debugger = executionEvent.getDebugger();
-                                performWork();
-                                executionEvent = null;
-                            }
-                        }).onEvent(new com.oracle.truffle.api.vm.EventConsumer<SuspendedEvent>(SuspendedEvent.class) {
-                            @Override
-                            protected void on(SuspendedEvent event) {
-                                suspendedEvent = event;
-                                performWork();
-                                suspendedEvent = null;
-                            }
-                        }).build();
+
+        ConsoleHandler consoleHandler = new DefaultConsoleHandler(System.in, out);
+        ContextInfo info = ContextInfo.createNoRestore(Client.R, null, ContextKind.SHARE_NOTHING, null, consoleHandler);
+        engine = info.createVM(PolyglotEngine.newBuilder().setOut(out).setErr(err));
+        debugger = Debugger.find(engine);
+        debuggerSession = debugger.startSession(event -> {
+            suspendedEvent = event;
+            performWork();
+            suspendedEvent = null;
+        });
+
         run.clear();
     }
 
     @After
     public void dispose() {
+        debuggerSession.close();
         if (engine != null) {
             engine.dispose();
         }
@@ -122,31 +124,19 @@ public class FastRDebugTest {
     public void testBreakpoint() throws Throwable {
         final Source factorial = createFactorial();
 
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    assertNull(suspendedEvent);
-                    assertNotNull(executionEvent);
-                    com.oracle.truffle.api.source.LineLocation nMinusOne = factorial.createLineLocation(9);
-                    debugger.setLineBreakpoint(0, nMinusOne, false);
-                    executionEvent.prepareContinue();
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-            }
+        run.addLast(() -> {
+            assertNull(suspendedEvent);
+            assertNotNull(debuggerSession);
+            Breakpoint breakpoint = Breakpoint.newBuilder(factorial).lineIs(9).build();
+            debuggerSession.install(breakpoint);
         });
+        // Init before eval:
+        performWork();
         engine.eval(factorial);
         assertExecutedOK();
 
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                // the breakpoint should hit instead
-            }
-        });
         assertLocation(9, "nMinusOne = n - 1",
-                        "n", 2.0);
+                        "n", "2.0");
         continueExecution();
 
         final Source evalSrc = RSource.fromTextInternal("main()\n", RSource.Internal.DEBUGTEST_DEBUG);
@@ -164,13 +154,10 @@ public class FastRDebugTest {
         engine.eval(factorial);
 
         // @formatter:on
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                assertNull(suspendedEvent);
-                assertNotNull(executionEvent);
-                executionEvent.prepareStepInto();
-            }
+        run.addLast(() -> {
+            assertNull(suspendedEvent);
+            assertNotNull(debuggerSession);
+            debuggerSession.suspendNextExecution();
         });
 
         assertLocation(2, "res = fac(2)");
@@ -185,6 +172,7 @@ public class FastRDebugTest {
         assertLocation(11, "res = n * nMOFact",
                         "n", 2.0, "nMinusOne", 1.0,
                         "nMOFact", 1.0);
+        assertMetaObjects(factorial, "n", "double", "nMOFact", "double", "nMinusOne", "double");
         stepOver(1);
         assertLocation(12, "res",
                         "n", 2.0,
@@ -197,6 +185,8 @@ public class FastRDebugTest {
         assertLocation(3, "res", "res", 2.0);
         stepOut();
 
+        // Init before eval:
+        performWork();
         final Source evalSource = RSource.fromTextInternal("main()\n", RSource.Internal.DEBUGTEST_EVAL);
         final Value value = engine.eval(evalSource);
         assertExecutedOK();
@@ -206,6 +196,38 @@ public class FastRDebugTest {
         assertEquals("Factorial computed OK", 2, n.intValue());
     }
 
+    @Test
+    public void testFindMetaObjectAndSourceLocation() throws Throwable {
+        final Source source = RSource.fromTextInternal("main <- function() {\n" +
+                        "  i = 3L\n" +
+                        "  n = 15\n" +
+                        "  str = 'hello'\n" +
+                        "  i <- i + 1L\n" +
+                        "  i\n" +
+                        "}\n",
+                        RSource.Internal.DEBUGTEST_DEBUG);
+        engine.eval(source);
+
+        // @formatter:on
+        run.addLast(() -> {
+            assertNull(suspendedEvent);
+            assertNotNull(debuggerSession);
+            debuggerSession.suspendNextExecution();
+        });
+
+        stepInto(1);
+        stepOver(3);
+        assertLocation(6, "i", "i", 4, "n", 15.0, "str", "hello");
+        assertMetaObjects(source, "i", "integer", "n", "double", "str", "character");
+        stepOut();
+        performWork();
+
+        final Source evalSource = RSource.fromTextInternal("main()\n", RSource.Internal.DEBUGTEST_EVAL);
+        engine.eval(evalSource);
+
+        assertExecutedOK();
+    }
+
     private void performWork() {
         try {
             if (ex == null && !run.isEmpty()) {
@@ -218,74 +240,48 @@ public class FastRDebugTest {
     }
 
     private void stepOver(final int size) {
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                suspendedEvent.prepareStepOver(size);
-            }
-        });
+        run.addLast(() -> suspendedEvent.prepareStepOver(size));
     }
 
     private void stepOut() {
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                suspendedEvent.prepareStepOut();
-            }
-        });
+        run.addLast(() -> suspendedEvent.prepareStepOut());
     }
 
     private void continueExecution() {
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                suspendedEvent.prepareContinue();
-            }
-        });
+        run.addLast(() -> suspendedEvent.prepareContinue());
     }
 
     private void stepInto(final int size) {
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                suspendedEvent.prepareStepInto(size);
-            }
-        });
+        run.addLast(() -> suspendedEvent.prepareStepInto(size));
     }
 
     private void assertLocation(final int line, final String code, final Object... expectedFrame) {
-        run.addLast(new Runnable() {
-            @Override
-            public void run() {
-                assertNotNull(suspendedEvent);
-                final int actualLine = suspendedEvent.getNode().getSourceSection().getLineLocation().getLineNumber();
-                Assert.assertEquals(line, actualLine);
-                final String actualCode = suspendedEvent.getNode().getSourceSection().getCode();
-                Assert.assertEquals(code, actualCode);
-                final MaterializedFrame frame = suspendedEvent.getFrame();
-
-                Assert.assertEquals(expectedFrame.length / 2, frameSize(frame));
-
-                for (int i = 0; i < expectedFrame.length; i = i + 2) {
-                    final String expectedIdentifier = (String) expectedFrame[i];
-                    final FrameSlot slot = frame.getFrameDescriptor().findFrameSlot(expectedIdentifier);
-                    Assert.assertNotNull(slot);
-                    final Object expectedValue = expectedFrame[i + 1];
-                    final Object actualValue = getRValue(frame.getValue(slot));
-                    Assert.assertEquals(expectedValue, actualValue);
-                }
-                run.removeFirst().run();
-            }
+        run.addLast(() -> {
+            assertNotNull(suspendedEvent);
+            final int currentLine = suspendedEvent.getSourceSection().getStartLine();
+            assertEquals(line, currentLine);
+            final String currentCode = suspendedEvent.getSourceSection().getCode().trim();
+            assertEquals(code, currentCode);
+            final DebugStackFrame frame = suspendedEvent.getTopStackFrame();
 
-            private int frameSize(MaterializedFrame frame) {
-                int cnt = 0;
-                for (FrameSlot slot : frame.getFrameDescriptor().getSlots()) {
-                    if (slot.getIdentifier() instanceof String) {
-                        cnt++;
-                    }
-                }
-                return cnt;
+            final AtomicInteger numFrameVars = new AtomicInteger(0);
+            frame.forEach(var -> {
+                numFrameVars.incrementAndGet();
+            });
+            // There is (self) among the variables, hence substract 1:
+            assertEquals(expectedFrame.length / 2, numFrameVars.get() - 1);
+
+            for (int i = 0; i < expectedFrame.length; i = i + 2) {
+                String expectedIdentifier = (String) expectedFrame[i];
+                Object expectedValue = expectedFrame[i + 1];
+                String expectedValueStr = (expectedValue != null) ? expectedValue.toString() : null;
+                DebugValue value = frame.getValue(expectedIdentifier);
+                assertNotNull(value);
+                String valueStr = value.as(String.class);
+                assertEquals(expectedValueStr, valueStr);
             }
+
+            run.removeFirst().run();
         });
     }
 
@@ -308,4 +304,35 @@ public class FastRDebugTest {
         }
         assertTrue("Assuming all requests processed: " + run, run.isEmpty());
     }
+
+    private void assertMetaObjects(final Source expectedSource, final String... nameAndMetaObjectPairs) {
+        run.addLast((Runnable) () -> {
+            DebugStackFrame frame = suspendedEvent.getTopStackFrame();
+            for (int i = 0; i < nameAndMetaObjectPairs.length;) {
+                String name = nameAndMetaObjectPairs[i++];
+                String expectedMO = nameAndMetaObjectPairs[i++];
+                boolean found = false;
+                for (DebugValue value : frame) {
+                    if (name.equals(value.getName())) {
+                        DebugValue moDV = value.getMetaObject();
+                        if (moDV != null || expectedMO != null) {
+                            String mo = moDV.as(String.class);
+                            Assert.assertEquals("MetaObjects of '" + name + "' differ:", expectedMO, mo);
+                        }
+                        found = true;
+                        // Trigger findSourceLocation() call
+                        SourceSection sourceLocation = value.getSourceLocation();
+                        if (sourceLocation != null) {
+                            Assert.assertSame("Sources differ", expectedSource, sourceLocation.getSource());
+                        }
+                    }
+                }
+                if (!found) {
+                    Assert.fail("DebugValue named '" + name + "' not found.");
+                }
+            }
+            run.removeFirst().run();
+        });
+    }
+
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java
index 11fdfeb85a3f1c7c935b7ac1e56c2c1fad419eb4..1d79ee857fc804394e83d3bd71097fbca34f8cbd 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java
@@ -29,13 +29,19 @@ import org.junit.Test;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.api.vm.PolyglotEngine.Builder;
+import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RSource;
+import com.oracle.truffle.r.runtime.context.ConsoleHandler;
+import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
+import com.oracle.truffle.r.test.generate.FastRSession.TestConsoleHandler;
 import com.oracle.truffle.tck.TruffleTCK;
 
 public class FastRTckTest extends TruffleTCK {
     @Test
     public void testVerifyPresence() {
-        PolyglotEngine vm = PolyglotEngine.newBuilder().build();
+        PolyglotEngine vm = PolyglotEngine.newBuilder().globalSymbol(ContextInfo.GLOBAL_SYMBOL,
+                        null).build();
         assertTrue("Our language is present", vm.getLanguages().containsKey("text/x-r"));
     }
 
@@ -134,6 +140,19 @@ public class FastRTckTest extends TruffleTCK {
         "isExecutableOfForeign <- function(o) {\n" +
         "  .fastr.interop.toBoolean(.fastr.interop.isExecutable(o))\n" +
         "}\n" +
+        "intValue <- function() 42L\n" +
+        "intVectorValue <- function() c(42L, 40L)\n" +
+        "intSequenceValue <- function() 42:50\n" +
+        "intType <- function() 'integer'\n" +
+        "doubleValue <- function() 42.1\n" +
+        "doubleVectorValue <- function() c(42.1, 40)\n" +
+        "doubleSequenceValue <- function() 42.1:50\n" +
+        "doubleType <- function() 'double'\n" +
+        "functionValue <- function() { function(x) 1 }\n" +
+        "functionType <- function() 'closure'\n" +
+        "builtinFunctionValue <- function() `+`\n" +
+        "builtinFunctionType <- function() 'builtin'\n" +
+        "valueWithSource <- function() intValue\n" +
         "for (name in ls()) .fastr.interop.export(name, get(name))\n",
         RSource.Internal.TCK_INIT
     );
@@ -141,7 +160,9 @@ public class FastRTckTest extends TruffleTCK {
 
     @Override
     protected PolyglotEngine prepareVM(Builder builder) throws Exception {
-        PolyglotEngine vm = builder.build();
+        ConsoleHandler consoleHandler = new TestConsoleHandler();
+        ContextInfo info = ContextInfo.createNoRestore(Client.R, null, ContextKind.SHARE_NOTHING, null, consoleHandler);
+        PolyglotEngine vm = info.createVM(builder);
         vm.eval(INITIALIZATION);
         return vm;
     }
@@ -473,12 +494,16 @@ public class FastRTckTest extends TruffleTCK {
 
     @Override
     protected String[] metaObjects() {
-        return null; // TBD add proper impl here.
+        return new String[]{
+                        "intValue", "intType", "intVectorValue", "intType", "intSequenceValue", "intType",
+                        "doubleValue", "doubleType", "doubleVectorValue", "doubleType", "doubleSequenceValue", "doubleType",
+                        "functionValue", "functionType",
+                        "builtinFunctionValue", "builtinFunctionType"};
     }
 
     @Override
     protected String valueWithSource() {
-        return null; // TBD add proper impl here.
+        return "valueWithSource";
     }
 
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java
new file mode 100644
index 0000000000000000000000000000000000000000..85f600102edbe908fc920d4cf39986245b44a250
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.tools;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import com.oracle.truffle.r.nodes.ffi.RFFIUpCallMethod;
+import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI;
+
+/**
+ * Generates the entries for {@link RFFIUpCallMethod}.
+ */
+public class RFFIUpCallMethodGenerate {
+
+    public static void main(String[] args) {
+        Method[] methods = UpCallsRFFI.class.getMethods();
+
+        Arrays.sort(methods, new Comparator<Method>() {
+
+            @Override
+            public int compare(Method a, Method b) {
+                return a.getName().compareTo(b.getName());
+            }
+
+        });
+        for (int i = 0; i < methods.length; i++) {
+            Method m = methods[i];
+            String sig = getNFISignature(m);
+            System.out.printf("%s(\"%s\")%s%n", m.getName(), sig, i == methods.length - 1 ? ";" : ",");
+        }
+
+    }
+
+    private static String getNFISignature(Method m) {
+        Class<?>[] paramTypes = m.getParameterTypes();
+        Annotation[][] annotations = m.getParameterAnnotations();
+        StringBuilder sb = new StringBuilder();
+        sb.append('(');
+        for (int i = 0; i < paramTypes.length; i++) {
+            Class<?> paramType = paramTypes[i];
+            String nfiParam = nfiParamName(paramType, annotations[i]);
+            sb.append(nfiParam);
+            if (i != paramTypes.length - 1) {
+                sb.append(", ");
+            }
+        }
+        sb.append(')');
+        sb.append(" : ");
+        sb.append(nfiParamName(m.getReturnType(), new Annotation[0]));
+        return sb.toString();
+    }
+
+    static String nfiParamName(Class<?> paramType, Annotation[] annotation) {
+        String paramName = paramType.getSimpleName();
+        Class<?> klass = annotation.length == 0 ? null : annotation[0].annotationType();
+        switch (paramName) {
+            case "Object":
+                return klass == null ? "object" : "pointer";
+            case "int":
+                return "sint32";
+            case "double":
+                return "double";
+            case "void":
+                return "void";
+            default:
+                return "object";
+        }
+
+    }
+
+}
diff --git a/documentation/dev/Index.md b/documentation/dev/Index.md
index 716c8d2c65d4e276c96f044f6bb32aea976c49a9..961fc13745c4fcf25519008157105b97e5512243 100644
--- a/documentation/dev/Index.md
+++ b/documentation/dev/Index.md
@@ -6,6 +6,6 @@
 * [Building](building.md)
 * [Testing](testing.md)
 * [R FFI Implementation](ffi.md)
-
-
+* [Cast pipelines](casts.md)
+* [Vector sharing](sharing.md) implementation of value semantics which avoids copying if possible.
 
diff --git a/documentation/dev/casts.md b/documentation/dev/casts.md
new file mode 100644
index 0000000000000000000000000000000000000000..a34394385304d479aeb153c6bb332ee12de3a67f
--- /dev/null
+++ b/documentation/dev/casts.md
@@ -0,0 +1,335 @@
+## Introduction
+
+Cast Pipelines (CP) are used to convert, validate and analyse input arguments of FastR builtins. The aim is to make the code in builtin specializations cleaner by relieving them from the burden of repeated argument handling that often leads to duplicate boilerplate code. Ideally, all argument handling code should be concentrated in a single method in a builtin. However, in certain situations, e.g. when a validation code evaluates more than one argument, the validation code cannot be moved to that single method.
+
+CP provides an API through which a _pipeline_ can be constructed declaratively for each builtin argument. This pipeline consists of one or more steps representing specific operations with the given argument. Because of the declarative character of the argument processing pipelines it is possible to retrieve additional information from the pipelines, which may be further used in tests or code analysis. For instance, each pipeline provides a set of output types, which may be used for coverage analysis of the builtin specializations, i.e. to check if no specialization is missing or unused. Also, in many cases it is possible to determine specific argument values from pipelines, such as default values, limit values of value intervals, and allowed or forbidden values (i.e. corner-case argument values). These specific values may be collected as argument samples and used to create automated tests of builtins. The argument samples are naturally divided into the positive and negative sample sets. The positive samples can be used to test the builtin's functionality and compare the result with the result of the builtin's GnuR counterpart. On the the other hand, the negative samples, which are assumed to cause an error in the FastR builtin, can be used to determine if the GnuR version fails too and produces the same error; if not, the pipeline must be redesigned to reflect the original.
+
+The following sections deal with the description of the CP API and with some implementation details.
+
+## Cast Pipelines API
+
+### Basics: usage in builtins
+
+CP API is an extension of the `CastBuilder` class, whose instance is passed as the argument of the `createCasts` method that can be overridden in a builtin class to define custom argument conversions for the builtin. The body of the `createCasts` method is the place where the cast pipelines are constructed for every argument of the builtin requiring some conversion or validation, as shown in the following listing.
+
+```java
+    @Override
+    protected void createCasts(CastBuilder casts) {
+        casts.arg("X").mustBe(numericValue(), RError.Message.X_NUMERIC);
+
+        casts.arg("m").asIntegerVector().
+                        findFirst().
+                        notNA();
+
+        casts.arg("n").asIntegerVector().
+                        findFirst().
+                        notNA();
+
+        casts.arg("na.rm").asLogicalVector().
+                        findFirst().
+                        map(toBoolean());
+    }
+```
+
+The CP API part for the pipeline construction is designed in the fluent-builder style. A new pipeline for an argument is initialized by calling the `arg` method on the `CastBuilder` instance. The `arg` method accepts either the index of the argument or the name of the argument, while the latter case is preffered. Following the `arg` method is a series of steps, each inserting a special Truffle node (`CastNode`) into the cast pipeline of the argument. The flow of a pipeline can be divided into four phases: _pre-initial_, _initial_, _coerced_ and _head_, while the last three are optional and each phase may consist of zero or more steps.
+
+In the **pre-initial** phase one can configure the overall behavior of the pipeline. Currently, only the default handling of `RNull` and `RMissing` values can be overridden (the default behavior is explained below). The pipeline can be configured using `PreinitialPhaseBuilder.conf(Consumer)` or any other method of the `PreinitialPhaseBuilder` class, e.g. `PreinitialPhaseBuilder.allowNull()`.
+
+An argument enters the **initial** phase as a generic object, which may be subjected to various assertions and conversions. The argument may, but may not, exit the initial phase as an instance of a specific type. The pipeline declared in the following listing specifies the default error of the pipeline and inserts one assertion node checking whether the argument is a non-null string. The argument exits this pipeline as a string represented by the `RAbstractStringVector` class. If any of the two conditions fails, the default error is raised.
+
+```java
+  casts.arg("m").defaultError(RError.Message.MUST_BE_STRING, "msg1").
+  mustBe(notNull().and(stringValue()));
+```
+
+The argument enters the **coerced** phase after having been processed by a node inserted by one of the `as_X_Vector` pipeline steps, where `X` is the type of the resulting vector. The input type of the argument corresponds to the used `as_X_Vector` step. The following example illustrates a pipeline, where the initial phase consists of one step (`asIntegerVector`) and the coerced phase has no step.
+
+```java
+casts.arg("m").asIntegerVector();
+```
+
+The next listing shows a pipeline having two steps belonging to the initial phase (i.e. `mustBe(stringValue()).asStringVector()`) and also two steps in the coerced phase (i.e. `mustBe(singleElement()).findFirst()`).
+
+```java
+  casts.arg("quote").
+  mustBe(stringValue()).
+  asStringVector().
+  mustBe(singleElement()).
+  findFirst();
+```
+
+The `singleElement()` condition requires that the string vector contain exactly one element. The `findFirst()` step retrieves the first element (the head) while exiting the coerced phase and entering the head phase.
+
+In the **head** phase, the argument value corresponds to the first element of the vector processed in the preceding coerced phase and may be handled basically by the same steps as in the initial phase, except the `as_X_Vector` steps. The head phase in the following example consists of two steps - `mustBe(notLogicalNA())` and `map(toBoolean())` - where the former asserts that the head of the logical vector argument must not be `NA` and the latter converts the logical value from the vector's head to the corresponding `boolean` value. The `findFirst` step in the coerced phase picks the head of the vector or returns the `RRuntime.LOGICAL_FALSE` in case the vector is empty.
+
+```java
+  casts.arg("na.encode").
+  asLogicalVector().
+  findFirst(RRuntime.LOGICAL_FALSE).
+  mustBe(notLogicalNA()).
+  map(toBoolean());
+```
+
+### Standalone usage
+
+One can use the same API to only create a cast node not necessarily associated with an argument and possibly outside of the Builtins world. Entry point of this API is the static method `CastNodeBuilder.newCastBuilder()` and the final invocation should be `createCastNode()`. Example:
+
+```java
+import com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder;
+...
+CastNode myCastNode = newCastBuilder().asStringVector().findFirst("default").buildCastNode();
+```
+
+### Steps
+
+The following subsections are dealing with the specific types of pipeline steps.
+
+#### Pseudosteps
+
+There are two steps that actually insert no node into the pipeline. The `defaultError(RError.Message message, Object... args)` step declares the default error of the pipeline and the `defaultWarning(RError.Message message, Object... args)` step declares the default warning of the pipeline. These default messages may be overridden further in the pipeline in the error or warning producing steps. All such steps have their overloaded variants for specifiying alternative messages.
+
+#### Modal Steps
+
+There are two modal steps - `mustBe` and `shouldBe` - that establish assertions on the argument value. If the assertion fails, the former raises an error, while the latter outputs a warning. If no message is specified, the default one is used. These steps may be used in all phases.
+
+The assertion conditions are passed as the first argument of those steps and must match the context argument type, which is `java.lang.Object` initially and may be made more specific further in the pipeline by certain steps, among which is also the `mustBe` one. The conditions are objects implementing the `ArgumentFilter<T, R extends T>` interface. Under normal circumstances, the user is not supposed to implement custom conditions. Instead, there is a set of predefined conditions in the `CastBuilder.Predef` class, which should contain all conditions occuring in the original GnuR code, although some may be missing.
+
+```java
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*
+```
+
+The `ArgumentFilter<T, R extends T>` contains the logical operators `and`, `or` and `not`, which allows constructing more complex assertions from the elementary building blocks, as shown in the following listing. The expression asserts that the argument value must be a non-null string or logical value.
+
+```java
+casts.arg("msg1").mustBe(notNull().and(stringValue().or(logicalValue())));
+```
+
+The `mustBe` step changes the context argument type of the argument in the following steps accordingly to the used filter expression. For example, in the following pipeline the `mustBe` step asserts that the argument must be a vector. This assertion narrows the context argument type in the following steps to `RAbstractVector`. Therefore, the conditions requiring a vector as the input value, such as `size`, may be used in the subsequent `shouldBe` step.
+
+```java
+casts.arg("x").mustBe(abstractVectorValue()).shouldBe(size(2));
+```
+
+#### Mapping Steps
+
+The mapping steps allow converting the argument from one type to another using the so-called mappers passed as the argument of those steps. There are two mapping steps: `map` and `mapIf`. The former always converts the argument using the mapper object passed as the first argument, while the latter converts the argument only if the condition passed as the first argument is `true`. The mapper object implements the `ArgumentMapper<S, R>` interface, nevertheless, just as in the case of the filter conditions, the user is not expected to implement custom ones, since the `CastBuilder.Predef` class should contain all necessary mappers.
+
+The mapping steps may be used in all phases except the coerced phase, for the time being.
+
+The signatures of the mapping steps are:
+
+```java
+map(ArgumentMapper<T, S> mapFn)
+mapIf(ArgumentFilter<? super T, ? extends S> argFilter, ArgumentMapper<S, R> mapFn)
+```
+
+A usage of the unconditional is illustrated in the following listing, where a logical value is mapped to a boolean value using the `toBoolean()` mapper. Since the unconditional mapping changes the context argument type according to the output type of the used mapper, it is possible to append the `shouldBe` modal step with the `trueValue()` filter requiring a boolean value on its input.
+
+```java
+  casts.arg("na.rm").
+  asLogicalVector().
+  findFirst().
+  map(toBoolean()).
+  shouldBe(trueValue());
+```
+
+In the following pipeline **only** null values are converted to the empty string in the initial phase. In contrast to the unconditional mapping, the conditional mapping does not change the context type.
+
+```java
+casts.arg("quote").mapIf(nullValue(), constant(""));
+```
+
+#### Vector Coercion Steps
+
+The vector coercion steps coerce the input argument value to the specified vector type. These steps can be used in the initial phase only. There are the following steps available:
+
+*   `asIntegerVector()`: coerces the input value to `RAbstractIntVector`
+*   `asDoubleVector()`: coerces the input value to `RAbstractDoubleVector`
+*   `asLogicalVector()`: coerces the input value to `RAbstractLogicalVector`
+*   `asStringVector()`: coerces the input value to `RAbstractStringVector`
+*   `asVector()`: coerces the input value to `RAbstractVector`
+
+All these steps terminate the initial phase and start the coerced phase.
+
+#### findFirst
+
+The `findFirst` step retrieves the first element from the vector argument. The output type corresponds to the element type of the vector.
+
+This step is available in the coerced phase only. It comes in a couple of flavours, which differ in how they handle a missing first element.
+
+```java
+findFirst()
+findFirst(RError.Message message, Object... messageArgs)
+<E>findFirst(E defaultValue)
+<E>findFirst(E defaultValue, RError.Message message, Object... messageArgs)
+```
+
+The first variant raises the default error of the pipeline as long as the vector is empty, the second variant throws the error specified in its arguments, the third one returns the default value instead of raising an error and the fourth one returns the default value and prints the warning specified in its arguments.
+
+#### notNA
+
+The `notNA` step reacts on NA argument values. This step is available in the initial and head phases only and also comes in four flavours.
+
+```java
+notNA()
+notNA(RError.Message message, Object... messageArgs)
+notNA(T naReplacement)
+notNA(T naReplacement, RError.Message message, Object... messageArgs)
+```
+
+Analogously to the findFirst step, the no-arg version throws the default error if the argument value is NA, while the second version throws the specified error. The next two versions return the `naReplacement` value, instead of raising an exception, while the last version prints the specified warning.
+
+The notNA step does not change the context argument type.
+
+### Handling of RNull and RMissing values
+
+By default, `RNull` and `RMissing` argument values are sent to the pipeline. While most of the pipeline cast nodes ignore those values and let them pass through, there are some nodes that may perform some transformation of those values. For example, the `FindFirstNode` node replaces both `RNull` and `RMissing` by the replacement values specified in the corresponding `findFirst(repl)` pipeline step. Also the `CastToVectorNode` coercion node replaces those values by an empty list provided that the `isPreserveNonVector` flag is set.
+
+The following list summarizes the behavior of a couple of pipeline steps with regard to the special values:
+
+*   `as<TYPE>()` coercions: RNull/RMissing passing through
+*   `findFirst`: RNull/RMissing treated as an empty vector, i.e. if the default value is specified it is used as a replacement for the special value, otherwise an error is raised.
+*   `notNA`: RNull/RMissing passing through
+*   `mustBe`, `shouldBe`: the filter condition determines whether RNull/RMissing is let through, e.g. `mustBe(stringValue())` blocks NULL since it is obviously not a string value. On the other hand, `shouldBe(stringValue())` lets the NULL through.
+*   `mapIf`: the condition behaves accordingly to the used filter (in the 1st parameter). For example, step `mapIf(stringValue(), constant(0), constant(1))` maps NULL to 1.
+
+The following cast pipeline examples aim to elucidate the behavior concerning the special values.
+
+Neither NULL nor MISSING pass through the pipeline:
+
+```java
+    cb.arg("x").mustBe(stringValue());
+```
+
+Therefore, the `mustNotBeNull` step in the following pipeline is redundant:
+
+```java
+    cb.arg("x").mustNotBeNull().mustBe(stringValue());
+```
+
+Both NULL and MISSING pass through the pipeline:
+
+```java
+    cb.arg("x").mustBe(stringValue().not());
+```
+
+NULL does not pass through the pipeline. MISSING passes through.
+
+```java
+    cb.arg("x").mustNotBeNull().mustBe(stringValue().not());
+```
+
+The same as above:
+
+```java
+    cb.arg("x").mustBe(nullValue().not().and(stringValue().not()));
+```
+
+Neither NULL nor MISSING pass through the pipeline:
+
+```java
+    cb.arg("x").asStringVector().mustBe(singleElement());
+```
+
+#### Overriding the default behavior
+
+A cast pipeline can be configured not to send `RNull` and/or `RMissing` to the cast nodes forming the cast pipeline. Then those values either bypass the pipeline, being eventually transformed to some constant, or an error is raised. One can use the following steps in the pre-initial phase to override the default behavior:
+
+*   `allowNull` - RNull bypasses the pipeline
+*   `mustNotBeNull(errorMsg)` - the error with errorMsg is raised when the input argument is `RNull`
+*   `mapNull(mapper)` - `RNull` is transformed using the mapper. The `RNull` replacement bypasses the pipeline.
+
+Analogous methods exist for `RMissing`.
+
+#### Optimizing the default behavior
+
+The above-mentioned overriding configurations may also be applied behind-the-scenes as optimization of the pipelines with certain structure. For instance, `allowNull()` may be activated if the pipeline contains no `RNull/RMissing` handling cast node, such as `FindFirstNode` or `CastToVectorNode`. The `mustNotBeNull` configuration may optimize pipelines containing cast nodes raising an error for `RNull/RMissing`, such as the nodes produced by steps `findFirst()`, `findFirst(error)` or `mustBe(singleElement())`. Or the `mapNull(x)` configuration may be applied provided that the pipeline's last step is `findFirst(x)`.
+
+### Cast Pipeline Optimizations
+
+The declarative character of cast pipelines allows for a number of optimizations done during the pipeline construction (some of them are mentioned in the previous section).
+
+#### FindFirst optimization
+
+Provided that the pipeline contains the `findFirst(x)` step specifying the replacement `x`, than the `RNull/RMissing` values are routed directly before the `FindFirstNode`. If the pipeline contains the overloaded versions `findFirst()` or `findFirst(error)`, the pipeline is configured to throw the error associated with the `FindFirstNode` for `RNull/RMissing` argument values.
+
+#### Scalar values optimization
+
+String, double and integer argument values are routed directly after the `FindFirstNode`. On the other hand, logical values bypass the whole pipeline provided that the pipeline ends by the pattern `asLogicalVector()...findFirst().map(toBoolean())`.
+
+### Sample Builtins Using Cast Pipelines
+
+* [Scan.java](../../com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java)
+* [NGetText.java](../../com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NGetText.java)
+
+### Using `rbdiag` tool
+
+The `mx rbdiag` tool implements the functionality of the static and dynamic stages of the chimney sweeping. This command prints a brief report for each cast pipeline defined in a given builtin.
+
+#### Static stage
+
+In the case of the static diagnostics the tool provides information about all possible result types of each argument and how those result types are bound to the corresponding arguments of the builtin's specializations. Importantly, the report can reveal unbound argument types that can potentially cause the missing specialization error.
+
+It can be illustrated on the `rowsum_matrix` builtin. The `mx` command is then as follows:
+
+```bash
+mx rbdiag rowsum_matrix
+```
+
+It prints a rather lengthy report, of which the following snippet shows the diagnostics of the `x` argument cast pipeline:
+
+```bash
+ Pipeline for 'x' (arg[0]):  
+  Result types union:  
+   [Integer, RAbstractIntVector, RAbstractDoubleVector, Double]  
+  Bound result types:  
+   potential (RAbstractIntVector->RVector) in Object rowsum(*RVector*,RVector,RVector,boolean,RStringVector)  
+   potential (RAbstractDoubleVector->RVector) in Object rowsum(*RVector*,RVector,RVector,boolean,RStringVector)  
+  Unbound types:  
+   [Integer, Double]  
+```
+
+The `Result types union` section lists all result types possibly produced by the pipeline. The `Bound result types` section outlines all bound type; i.e. the argument types for which there is a corresponding specialization in the builtin. In this case, only two argument types - `RAbstractIntVector` and `RAbstractDoubleVector` - are bound to the `rowsum(RVector,RVector,RVector,boolean,RStringVector)` specialization. (The asterisks surrounding the first argument in the specialization indicate the argument to which the type in question is bound). The `potential` flag indicates here that there is an underlying implicit conversion between the type produced by the cast pipeline and the argument type in the specialization.
+
+Nevertheless, there are two arguments left unbound - `Integer` and `Double`. This problem can be easily healed by using the abstract vector types instead of the concrete ones. The following report snippet shows the diagnostics of the same `x` argument:
+
+```bash
+ Pipeline for 'x' (arg[0]):  
+  Result types union:  
+   [Integer, RAbstractIntVector, RAbstractDoubleVector, Double]  
+  Bound result types:  
+   full (RAbstractIntVector->RAbstractVector) in Object rowsum(*RAbstractVector*,RAbstractVector,RAbstractVector,boolean,RAbstractStringVector)  
+   potential (Double->RAbstractVector) in Object rowsum(*RAbstractVector*,RAbstractVector,RAbstractVector,boolean,RAbstractStringVector)  
+   full (RAbstractDoubleVector->RAbstractVector) in Object rowsum(*RAbstractVector*,RAbstractVector,RAbstractVector,boolean,RAbstractStringVector)  
+   potential (Integer->RAbstractVector) in Object rowsum(*RAbstractVector*,RAbstractVector,RAbstractVector,boolean,RAbstractStringVector)  
+  Unbound types:  
+   []
+```
+
+The produced result types are naturally the same ones, but now all of them are bound. In conclusion, using the abstract types resulted in the binding of the previously unbound types.
+
+Note: The `full` flag indicates that the pipeline's type is a subtype of the specialization's argument type. The `partial` flag, which is not seen here, indicates that the pipeline's type is a supertype of the specialization's argument type. The `potential` flag indicates an implicit conversion or a potentially non-empty intersection between the two types, typically if they are both interfaces.
+
+#### Dynamic stage
+
+In the dynamic stage, the tool uses the samples inferred from the cast pipelines of a given builtin along with some 'springboard' list of valid arguments to construct a number of argument combinations. These argument lists are then used to invoke both the FastR builtin and its GnuR counterpart. The tool uses the test output file (ExpectedTestOutput.test) to obtain the 'springboard' argument lists for a given builtin. These valid argument lists are reproduced by substituting combinations of generated samples. The varied arguments are then used against both GnuR and FastR. If the two outputs differ, the tool reports the command and the corresponding outputs.
+
+The tool can be run from the command line via the mx command:
+
+```bash
+mx rbdiag colSums --sweep
+```
+
+To filter out stack traces, the error output can be redirected as follows:
+
+```bash
+mx rbdiag colSums --sweep 2> /dev/null
+```
+
+The following command sweeps all builtins using a less strict method for comparing FastR and GNUR outputs (`–matchLevel=error`), according to which two outputs are considered matching if both contain `Error` or none of them contains `Error`.
+
+```bash
+mx rbdiag --sweep --mnonly --matchLevel=error --maxSweeps=30 --outMaxLev=0
+```
+
+The command also ignores the samples yielded by the cast pipelines and uses `RNull` and `RMissing` as the only samples for all arguments (`–mnonly`). The `--maxSweeps=30` restricts the maximum number of sweeps per builtin to 30 and the `--outMaxLev=0` option sets the least detailed level of verbosity.
diff --git a/documentation/dev/ffi.md b/documentation/dev/ffi.md
index 0be78c5bacccd8fc4563b4da07e17bf5c9c1c6a3..1ebb04860b47e5d8dcf7f51ea3f9edf0b8c81270 100644
--- a/documentation/dev/ffi.md
+++ b/documentation/dev/ffi.md
@@ -1,7 +1,11 @@
 # The R FFI Implementation
 
 # Introduction
-The implementation of the [R FFI](https://cran.r-project.org/doc/manuals/r-release/R-exts.html) is contained in the `fficall` directory of
+FastR interfaces to native C and Fortran code in a number of ways, for example, access to C library APIs not supported by the Java JDK, access to LaPack functions, and the `.Call`, `.Fortran`, `.C` builtins. Each of these are defined by a Java interface,e.g. `CallRFFI` for the `.Call` builtin. To facilitate experimentation and different implementations, the implementation of these interfaces is defined by a factory class, `RFFIFactory`, that is chosen at run time via the `fastr.ffi.factory.class` system property. The factory is responsible for creating an instance of the `RFFI` interface that in turn provides access to implementations of the underlying interfaces such as `CallRFFI`. This structure allows
+for each of the individual interfaces to be implemented by a different mechanism. Currently the default factory class is `JNI_RFFIFactory` which uses the Java JNI system to implement the transition to native code.
+
+# Native Implementation
+The native implementation of the [R FFI](https://cran.r-project.org/doc/manuals/r-release/R-exts.html) is contained in the `fficall` directory of
 the `com.oracle/truffle.r.native` project`. It's actually a bit more than that as it also contains code copied from GNU R, for example that supports graphics or is sufficiently
 simple that it is neither necessary nor desirable to implement in Java. As this has evolved a better name for `fficall` would probably be `main`
 for compatibility with GNU R.
@@ -9,9 +13,8 @@ for compatibility with GNU R.
  There are four sub-directories in `fficall/src`:
  * `include`
  * `common`
- * `variable_defs`
  * `jni`
- * `truffle`
+ * `truffle_llvm`
 
 ## The `fficall/include` directory
 
@@ -40,15 +43,16 @@ angle bracket form.
 copied/included from GNU R. N.B. Some modified files have a `_fastr` suffix to avoid a clash with an existing file in GNU R that would match
 the Makefile rule for compiling directly from the GNU R file.
 
-## The `variable_defs` directory
-
-The GNU R FFI defines a large number of (extern) variables the definitions of which, in GNU R, are scattered across the source files.
-In FastR these are collected into one file, `variable_defs.h`. However, the actual initialization of the variables is, in general, implementation
-dependent. In order to support a JNI and a non-JNI implementation, the file is stored in a separate directory.
-
 ## The `jni` directory
 `jni` contains the implementation that is based on and has explicit dependencies on Java JNI. It is described in more detail [here](jni_ffi.md)
 
-## The `truffle` directory
+## The `truffle_llvm` directory
+
+`truffle_llvm` contains the native side of the variant that is based on the Truffle LLVM implementation. It is described in more detail [here](truffle_llvm_ffi.md)
+
+# RFFI Initialization
+Not all of the individual interfaces need to be instantiated on startup. The `getXXXRFFI()` method of `RFFI` is responsible for instantiating the `XXX` interface (e.e.g `Call`).
+However, the factory can choose to instantiate the interfqces eagerly if desired. The choice of factory class is made by `RFFIFactory.initialize()` which is called when the
+initial `RContext` is being created by `PolyglotEngine`. Note that at this stage, very little code can be executed as the initial context has not yet been fully created and registered with `PolyglotEngine`.
 
-`truffle` contains the native side of the variant that is based on the Truffle LLVM implementation. It is described in more detail [here](truffle_ffi.md)
\ No newline at end of file
+In general, state maintained by the `RFFI` implementation classes is `RContext` specific and to facilitate this `RFFIFactory` defines a `newContextState` method that is called by `RContext`. Again, at the point this is called the context is not active and so any execution that requires an active context must be delayed until the `initialize` method is called on the `ContextState` instance. Typically special initialization may be required on the initialization of the initial context, such as loading native libraries, and also on the initialization of a `SHARED_PARENT_RW` context kind.
diff --git a/documentation/dev/sharing.md b/documentation/dev/sharing.md
new file mode 100644
index 0000000000000000000000000000000000000000..2f0a37814ee3474c15e54e69a161b24b4ac010fd
--- /dev/null
+++ b/documentation/dev/sharing.md
@@ -0,0 +1,74 @@
+Objects in FastR can be in three states: _temporary_, _non-shared_ and _shared_, this is handled through `RShareable` interface. Once an object is written into a frame (a variable) its state is transitioned from _temporary_ to _non-shared_ or from _non-shared_ to _shared_, this transition does not take place if LSH == RHS, e.g. `a <- a`. If some code is about to alter a _shared_ object, it must make a copy. _Temporary_ objects can be altered freely. _Non-shared_ objects can be altered in place in replacement functions, but otherwise should be copied as well. With this schema we can implement value semantics and avoid some expensive copying.
+
+Summary of the states: Temporary -> Non shared (at most one reference) -> Shared (may be referenced 2 or more places)
+
+### Reference counting for parameters
+
+TODO: to be documented.
+
+### Replacement functions
+
+following code:
+
+`a[1] <- 42`
+
+is rewritten by the parser to the following sequence:
+
+```r
+a <- `[<-`(a, 1, 42)
+```
+
+The replacement function can alter "`a"` as long as it is _non-shared_, then it returns the same instance and the write into the frame concludes LHS == RHS and does no state transition. If "a" is _non-shared_, but cannot be used as is, e.g. because we need to cast it to another type, the replacement returns fresh instance in _temporary_ state which will be transitioned to _non-shared_ by the write into the frame, because in that case LHS != RHS.
+
+### Complex data structures: lists and attributes
+
+Lists can contain other objects – like frame contains local variables, object in a list can be referenced through the list (like with local variable name). Moreover, because lists have value semantics (unlike environments), once we pass a list to a function as an argument "a" any changes to values inside "a", e.g. "a$f[[1]] <- 42" should not be visible from the outside. Example:
+
+```r
+x <- list(f = c(1,2,3))  
+foo <- function(a) a$f[[1]] <- 42  
+foo(x)  
+cat(x$f[[1]]) # should print 1, not 42
+```
+
+If we wanted to have consistent reference count for objects contained within lists, we would have to increment reference count of "x" and all items (recursively) inside x, which can be costly operation.
+
+Another problematic part are replacements where lists are involved:
+
+```r
+k$bar[1] <- 42
+```
+
+is rewritten as
+
+```r
+tmp <- `$`(k, 'bar')  
+tmp[1] <- 42  
+k <- `$<-`(k, 'bar', tmp)
+```
+
+If "k" is _non-shared_ and there is some other vector in k$foo which is also non-shared, we want it to stay non-shared after this operation to avoid possible future copying. Imagine that "k" does not yet have a field named "bar", this means that "k" has to be reallocated and the replacement will return different instance of RList (but the original RList will be lost after the replacement). If the reference counting is not done in smart way, "k$foo" will be marked as shared (referenced by list that is now in "k" and by the list we thrown away because original "k" needed to be reallocated).
+
+Note: everything in this section holds for attributes as well.
+
+### Deferred ref-count increment for list elements and attributes:
+
+Lists can hold elements that are not in a consistent state with respect to the sharing model. However, such elements are put into consistent state once they are read from the list, their state can be inferred from the state of the owning list:
+
+*   owner is shared -> element must be shared
+*   owner is non-shared -> element must be at least non-shared
+*   owner is temporary -> leave the element as is (can be even temporary?)
+
+Important observation here is that there is no possible way, how a list can contain a non-shared element not owned by it, given that any element of some other list must be first read and the extraction from list makes it at least non-shared and only then it can be put inside another list. On a write to a list, we do increment ref-count, so it will become shared.
+
+This means that <u>temporary</u> elements can be freely put into lists without incrementing their ref-count. Moreover, when a list is copied into another variable or passed as an argument to a function, we only have to increment the ref-count of the list (no recursion needed). This is how most of the code works now (e.g. putting temps to lists happens often in built-ins).
+
+The catch: now considering the internal Java code of buitins: reads and writes from a list should go through special nodes, unless they have certain properties: write of temporary to a list, or read only to peek at the element (e.g. calculate something from it) and then forget the reference (or at least not reveal it to the R user in an environment, attribute, or list), otherwise `ExtractListElement` node should be used for reads. In the case of writes: I have not found yet a code that would put potentially non-temporary data into a list.
+
+It seems that most of the internal code that works with lists actually has these properties.
+
+### Unresolved problem: cycles
+
+`l <- list(list()); l[[1]] <- l; l`, this currently crashes FastR, but GnuR can handle it, because they call `Fixup_RHS` before each assignment operation and this function traverses RHS to check if it contains reference to LSH (if so, makes a copy). This would mean a very costly list traversal on each assignment.
+
+We can remember for each list, if it is recursive, like we remember for vectors, if they contain `NA`. `RDataFactory.createList` would take `boolean isRecursive` (it is often known that newly created list only contains non-lists) and every update of a list would have to update that property accordingly.
diff --git a/documentation/dev/truffle_ffi.md b/documentation/dev/truffle_llvm_ffi.md
similarity index 100%
rename from documentation/dev/truffle_ffi.md
rename to documentation/dev/truffle_llvm_ffi.md
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 012e56015970dcfb0066ab7f11d1688a8630bd34..9ace1ab1d3a27e419cea334c91beb3be453f17cd 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -137,11 +137,10 @@ com.oracle.truffle.r.native/fficall/src/include/Fileio.h,gnu_r_gentleman_ihaka.c
 com.oracle.truffle.r.native/fficall/src/include/contour-common.h,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.native/fficall/src/include/nmath.h,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/include/rlocale.h,gnu_r_gentleman_ihaka.copyright
-com.oracle.truffle.r.native/fficall/src/variable_defs/variable_defs.h,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/jni/Memory.c,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/jni/pcre_rffi.c,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.native/fficall/src/jni/Rdynload_fastr.c,gnu_r.copyright
-com.oracle.truffle.r.native/fficall/src/truffle/Rdynload_fastr.c,gnu_r.copyright
+com.oracle.truffle.r.native/fficall/src/truffle_llvm/Rdynload_fastr.c,gnu_r.copyright
 com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c,gnu_r.copyright
 com.oracle.truffle.r.native/include/src/libintl.h,no.copyright
 com.oracle.truffle.r.native/library/base/src/registration.c,no.copyright
diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py
index ae23ab25f04efa2d6096f993195c49b6c4518656..5e9c6ebfd3344ee1405840869061861a8af54bc6 100644
--- a/mx.fastr/mx_fastr.py
+++ b/mx.fastr/mx_fastr.py
@@ -32,6 +32,7 @@ import mx_fastr_junit
 from mx_fastr_dists import FastRNativeProject, FastRTestNativeProject, FastRReleaseProject, FastRNativeRecommendedProject #pylint: disable=unused-import
 import mx_copylib
 import mx_fastr_mkgramrd
+import mx_fastr_edinclude
 
 import os
 
@@ -151,7 +152,7 @@ def set_graal_options():
 
 def _sulong_options():
     if _mx_sulong:
-        return ['-Dfastr.ffi.factory.class=com.oracle.truffle.r.engine.interop.ffi.Truffle_RFFIFactory',
+        return ['-Dfastr.ffi.factory.class=com.oracle.truffle.r.engine.interop.ffi.llvm.TruffleLLVM_RFFIFactory',
                 '-XX:-UseJVMCIClassLoader']
     else:
         return []
@@ -405,8 +406,11 @@ def _test_package():
 def _test_subpackage(name):
     return '.'.join((_test_package(), name))
 
+def _simple_generated_unit_tests():
+    return ','.join(map(_test_subpackage, ['library.base', 'library.grid', 'library.methods', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'parser', 'S4', 'rng', 'runtime.data']))
+
 def _simple_unit_tests():
-    return ','.join(map(_test_subpackage, ['library.base', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'tck', 'parser', 'S4', 'rng', 'runtime.data']))
+    return ','.join([_simple_generated_unit_tests(), _test_subpackage('tck')])
 
 def _package_unit_tests():
     return ','.join(map(_test_subpackage, ['rffi', 'rpackages']))
@@ -426,10 +430,13 @@ def _gate_unit_tests():
 def _all_unit_tests():
     return _gate_unit_tests()
 
+def _all_generated_unit_tests():
+    return ','.join([_simple_generated_unit_tests(), _package_unit_tests()])
+
 def testgen(args):
     '''generate the expected output for unit tests, and All/Failing test classes'''
     parser = ArgumentParser(prog='r testgen')
-    parser.add_argument('--tests', action='store', default=_all_unit_tests(), help='pattern to match test classes')
+    parser.add_argument('--tests', action='store', default=_all_generated_unit_tests(), help='pattern to match test classes')
     args = parser.parse_args(args)
     # check we are in the home directory
     if os.getcwd() != _fastr_suite.dir:
@@ -596,6 +603,7 @@ _commands = {
     'mkgramrd': [mx_fastr_mkgramrd.mkgramrd, '[options]'],
     'rcopylib' : [mx_copylib.copylib, '[]'],
     'rupdatelib' : [mx_copylib.updatelib, '[]'],
+    'edinclude' : [mx_fastr_edinclude.edinclude, '[]'],
     'gnu-r' : [gnu_r, '[]'],
     'gnu-rscript' : [gnu_rscript, '[]'],
     'nativebuild' : [nativebuild, '[]'],
diff --git a/mx.fastr/mx_fastr_compile.py b/mx.fastr/mx_fastr_compile.py
index 701f3c2a5f7689543111444151572e3865128520..94fac7e4f7dbb70935e2c1e220b35d9b46d62cf4 100644
--- a/mx.fastr/mx_fastr_compile.py
+++ b/mx.fastr/mx_fastr_compile.py
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -69,7 +69,7 @@ class AnalyzedArgs:
 
 
 def _c_dummy_file():
-    return os.path.join(mx_fastr._fastr_suite.dir, 'com.oracle.truffle.r.native', 'fficall', 'src', 'truffle', 'llvm_dummy.c')
+    return os.path.join(mx_fastr._fastr_suite.dir, 'com.oracle.truffle.r.native', 'fficall', 'src', 'truffle_llvm', 'llvm_dummy.c')
 
 def _analyze_args(args, dragonEgg=False):
     '''
diff --git a/mx.fastr/mx_fastr_edinclude.py b/mx.fastr/mx_fastr_edinclude.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc211cdd32c068b3fdf4ea24e1b4e0c0c2031209
--- /dev/null
+++ b/mx.fastr/mx_fastr_edinclude.py
@@ -0,0 +1,208 @@
+#
+# Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+from os.path import join
+
+'''
+Handles all the editing of R FFI header files from the GNUR include directory to the
+FastR include directory.
+'''
+# variables in Rinternals.h that are Java Objects and so remapped to functions
+r_internals_vars = ['R_NilValue', 'R_UnboundValue', 'R_MissingArg', 'R_GlobalEnv',
+    'R_EmptyEnv', 'R_BaseEnv', 'R_BaseNamespace', 'R_NamespaceRegistry', 'R_Srcref', 'R_Bracket2Symbol',
+    'R_BracketSymbol', 'R_BraceSymbol', 'R_ClassSymbol', 'R_DeviceSymbol', 'R_DevicesSymbol',
+    'R_DimNamesSymbol', 'R_DimSymbol', 'R_DollarSymbol', 'R_DotsSymbol', 'R_DropSymbol', 'R_LastvalueSymbol',
+    'R_LevelsSymbol', 'R_ModeSymbol', 'R_NameSymbol', 'R_NamesSymbol', 'R_NaRmSymbol', 'R_PackageSymbol',
+    'R_QuoteSymbol', 'R_RowNamesSymbol', 'R_SeedsSymbol', 'R_SourceSymbol', 'R_TspSymbol', 'R_dot_defined',
+    'R_dot_Method', 'R_dot_target', 'R_SrcrefSymbol', 'R_SrcfileSymbol', 'R_NaString', 'R_BlankString',
+    'R_BlankScalarString', 'R_BaseSymbol', 'R_baseSymbol', 'R_NamespaceEnvSymbol']
+
+interface_vars = ['R_Home', 'R_TempDir',]
+
+
+def edinclude(args):
+    '''
+    edit GNU include files for FASTR
+    args[0] path to GNUR include directory
+    '''
+    ed_r_internals(args[0])
+    ed_r_interface(args[0])
+    ed_graphicsengine(args[0])
+
+use_internals_section = '''#ifdef FASTR
+// packages defining USE_INTERNALS expect certain defs (e.g. isNull) to be there
+#ifdef USE_RINTERNALS
+#define USE_RINTERNALS_DEFS
+#endif
+#undef USE_RINTERNALS
+#else
+'''
+
+sexp = '''#ifdef FASTR
+typedef void *SEXP;
+#define DATAPTR(x)\t\tR_DATAPTR(x)
+void *(R_DATAPTR)(SEXP x);
+#else
+'''
+use_internals_begin = '''#if defined (USE_RINTERNALS_DEFS) && (defined (USE_RINTERNALS) || defined (FASTR))
+'''
+use_internals_end = '''#endif
+#ifdef USE_RINTERNALS
+
+'''
+preserveObject = '''#ifdef FASTR
+SEXP R_PreserveObject(SEXP);
+#else
+'''
+
+def ed_r_internals(gnu_dir):
+    r_internals_h = join(gnu_dir, 'Rinternals.h')
+    with open(r_internals_h) as f:
+        lines = f.readlines()
+
+    use_rinternals_count = 0
+    with open('Rinternals.h', 'w') as f:
+        for line in lines:
+            if '== USE_RINTERNALS section' in line:
+                f.write(use_internals_section)
+                f.write(line)
+                f.write('#endif\n')
+            elif 'typedef struct SEXPREC *SEXP' in line:
+                f.write(sexp)
+                f.write(line)
+                f.write('#endif\n')
+            elif '#ifdef USE_RINTERNALS' in line:
+                if use_rinternals_count > 0:
+                    f.write(use_internals_begin)
+                else:
+                    f.write(line)
+                    use_rinternals_count = 1
+            elif 'macro version of R_CheckStack' in line:
+                f.write(use_internals_end)
+                f.write(line)
+            elif 'R_PreserveObject' in line:
+                f.write(preserveObject)
+                f.write(line)
+                f.write('#endif\n')
+            elif 'LibExtern' in line:
+                var = is_internal_var(line)
+                if var:
+                    rewrite_var(f, var, line)
+                else:
+                    f.write(line)
+            elif 'R_RestartToken' in line:
+                f.write('#ifdef FASTR\n')
+                f.write('SEXP FASTR_R_RestartToken();\n')
+                f.write('#else\n')
+                f.write(line)
+                f.write('#endif\n')
+            else:
+                f.write(line)
+
+def rewrite_var(f, var, line):
+    f.write('#ifdef FASTR\n')
+    f.write('LibExtern SEXP FASTR_{0}();\n'.format(var))
+    if var == 'R_baseSymbol': # alias
+        f.write('#define {0} FASTR_R_BaseSymbol()\n'.format(var))
+    else:
+        f.write('#define {0} FASTR_{0}()\n'.format(var))
+    f.write('#else\n')
+    # Ugly special case, comment split on two lines, just
+    if var == 'R_EmptyEnv':
+        split = line.split(';')
+        f.write(split[0])
+        f.write(';\n')
+        f.write('#endif\n')
+        f.write(split[1])
+    else:
+        f.write(line)
+        f.write('#endif\n')
+
+def is_internal_var(line):
+    for var in r_internals_vars:
+        varsemi = var + ';'
+        if varsemi in line:
+            return var
+    return None
+
+context_defs = '''#ifdef FASTR
+typedef void *CTXT;
+typedef void *SEXP;
+extern CTXT FASTR_GlobalContext();
+#define R_GlobalContext FASTR_GlobalContext()
+extern CTXT R_getGlobalFunctionContext();
+extern CTXT R_getParentFunctionContext(CTXT);
+extern SEXP R_getContextEnv(CTXT);
+extern SEXP R_getContextFun(CTXT);
+extern SEXP R_getContextCall(CTXT);
+extern SEXP R_getContextSrcRef(CTXT);
+extern int R_insideBrowser();
+extern int R_isGlobal(CTXT);
+extern int R_isEqual(void*, void*);
+#else
+'''
+
+interactive_rewrite = '''#ifdef FASTR
+extern Rboolean FASTR_R_Interactive();
+#define R_Interactive FASTR_R_Interactive()
+#else
+'''
+
+rhome_rewrite = '''#ifdef FASTR
+extern char* FASTR_R_Home();
+#define R_Home FASTR_R_Home()
+#else
+'''
+
+def ed_r_interface(gnu_dir):
+    r_interface_h = join(gnu_dir, 'Rinterface.h')
+    with open(r_interface_h) as f:
+        lines = f.readlines()
+
+    with open('Rinterface.h', 'w') as f:
+        for line in lines:
+            if 'R_GlobalContext' in line:
+                f.write(context_defs)
+                f.write(line)
+                f.write('#endif\n')
+            elif 'R_Interactive' in line:
+                f.write(interactive_rewrite)
+                f.write(line)
+                f.write('#endif\n')
+            elif 'R_Home;' in line:
+                f.write(rhome_rewrite)
+                f.write(line)
+                f.write('#endif\n')
+            else:
+                f.write(line)
+
+def ed_graphicsengine(gnu_dir):
+    graphicsengine_h = join(gnu_dir, 'R_ext', 'GraphicsEngine.h')
+    with open(graphicsengine_h) as f:
+        lines = f.readlines()
+
+    with open(join('R_ext', 'GraphicsEngine.h'), 'w') as f:
+        for line in lines:
+            if 'MAX_GRAPHICS_SYSTEMS' in line:
+                f.write(line.replace('24', '256'))
+            else:
+                f.write(line)
diff --git a/mx.fastr/mx_fastr_mkgramrd.py b/mx.fastr/mx_fastr_mkgramrd.py
index 5ca3f5c4294770c6ec6badc4fd84a0233a24a1ee..a951e04a1491d38e3e2bc675e8ac292348565e0b 100644
--- a/mx.fastr/mx_fastr_mkgramrd.py
+++ b/mx.fastr/mx_fastr_mkgramrd.py
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,10 @@ def mkgramrd(args):
     converts GNU R gramRd.c into one suitable for invoking via FastR
     '''
     parse_defs = '''
-extern SEXP R_SrcrefSymbol;
-extern SEXP R_SrcfileSymbol;
+extern SEXP FASTR_R_SrcrefSymbol();
+#define R_SrcrefSymbol FASTR_R_SrcrefSymbol()
+extern SEXP FASTR_R_SrcfileSymbol();
+#define R_SrcfileSymbol FASTR_R_SrcfileSymbol()
 extern int R_ParseContextLast;
 #define R_EOF -1
 #define PARSE_ERROR_SIZE 256
@@ -37,7 +39,8 @@ static char    R_ParseContext[PARSE_CONTEXT_SIZE];
 int    R_ParseContextLast;
 int    R_ParseContextLine;
 int R_ParseError;
-extern SEXP R_EmptyEnv;
+extern SEXP FASTR_R_EmptyEnv();
+#define R_EmptyEnv FASTR_R_EmptyEnv()
 extern SEXP R_NewHashedEnv(SEXP a, SEXP b);
 
 char *dgettext(const char *p, const char *msgid) {
diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py
index 347e963809bda3f4b3530ec00eb103088bb3ae12..527fa89155eb5ea7769b46d68cadb34486156244 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -28,7 +28,7 @@ suite = {
     "suites" : [
             {
                "name" : "truffle",
-               "version" : "a440a1558baef3411705af24755a7c30221fc9ff",
+               "version" : "0a9e88293bf90fe485999b26b0969e71509a64aa",
                "urls" : [
                     {"url" : "https://github.com/graalvm/truffle", "kind" : "git"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -230,7 +230,7 @@ suite = {
     "com.oracle.truffle.r.runtime.ffi" : {
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.truffle.r.runtime",
+        "com.oracle.truffle.r.nodes",
       ],
       "checkstyle" : "com.oracle.truffle.r.runtime",
       "javaCompliance" : "1.8",
@@ -253,7 +253,6 @@ suite = {
     "com.oracle.truffle.r.library" : {
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.truffle.r.nodes",
         "com.oracle.truffle.r.runtime.ffi",
       ],
       "annotationProcessors" : [