diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java
index 60ce02957ff14524dedbc3be55bb6ca915e6bf8b..a254e1c6703c7857b428ef2cb8cefbc5b18f0a86 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPortBuiltin.java
@@ -29,7 +29,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
  * of the grid code in R.
  */
 @RBuiltin(name = ".fastr.grid.doSetViewPort", parameterNames = {"vp", "hasParent", "pushing"}, kind = RBuiltinKind.INTERNAL, behavior = RBehavior.COMPLEX)
-public abstract class DoSetViewPortBuiltin extends RBuiltinNode {
+public abstract class DoSetViewPortBuiltin extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(DoSetViewPortBuiltin.class);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
index 13a04235fc97a49935226cdae711577978f93e94..68b4977bee06b554c5949f43247f92c5dbfeafbb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/RBuiltinPackages.java
@@ -37,7 +37,6 @@ import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.r.nodes.builtin.base.BasePackage;
 import com.oracle.truffle.r.nodes.builtin.base.BaseVariables;
-import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.REnvVars;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -159,15 +158,8 @@ public final class RBuiltinPackages implements RBuiltinLookup {
     private static RootCallTarget createArgumentsCallTarget(RBuiltinFactory builtin) {
         CompilerAsserts.neverPartOfCompilation();
 
-        RBuiltinNode node = builtin.getConstructor().get();
-        FormalArguments formals = FormalArguments.createForBuiltin(node.getDefaultParameterValues(), builtin.getSignature());
-        if (builtin.getKind() == RBuiltinKind.INTERNAL) {
-            assert node.getDefaultParameterValues().length == 0 : "INTERNAL builtins do not need default values";
-            assert builtin.getSignature().getVarArgCount() == 0 || builtin.getSignature().getVarArgIndex() == builtin.getSignature().getLength() - 1 : "only last argument can be vararg";
-        }
-
         FrameDescriptor frameDescriptor = new FrameDescriptor();
-        RBuiltinRootNode root = new RBuiltinRootNode(builtin, node, formals, frameDescriptor, null);
+        RBuiltinRootNode root = new RBuiltinRootNode(builtin, frameDescriptor, null);
         FrameSlotChangeMonitor.initializeFunctionFrameDescriptor(builtin.getName(), frameDescriptor);
         return Truffle.getRuntime().createCallTarget(root);
     }
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 4a4a475317659bd2bdfa5b1493bb53e194b19b50..5930d40906f9b27ab93507d436d496c1d7a2b457 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 // TODO: add (permuted) dimnames to the result
 @RBuiltin(name = "aperm", kind = INTERNAL, parameterNames = {"a", "perm", "resize"}, behavior = PURE)
-public abstract class APerm extends RBuiltinNode {
+public abstract class APerm extends RBuiltinNode.Arg3 {
 
     private final BranchProfile emptyPermVector = BranchProfile.create();
     private final ConditionProfile mustResize = ConditionProfile.createBinaryProfile();
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 a1c904169a3ef20d1f36b251965793717dc27489..d12d0d396185590281e40b70bf973a6dceaba3a9 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
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "abbreviate", kind = INTERNAL, parameterNames = {"x", "minlength", "use.classes"}, behavior = PURE)
-public abstract class Abbrev extends RBuiltinNode {
+public abstract class Abbrev extends RBuiltinNode.Arg3 {
     private final NACheck naCheck = NACheck.create();
 
     static {
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 0feeb054e6b35da0b323f8c79e24c2b849778797..7a73125009e2d2c99480dfcbc6ecb84440a15b55 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
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 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 {
+public abstract class AllNames extends RBuiltinNode.Arg4 {
 
     static {
         Casts casts = new Casts(AllNames.class);
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 99ae59e01376b256adc4054d8c54c30b968de6e9..217ee20c8ec7163c7f1103833eef89499cdbad60 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "anyNA", kind = PRIMITIVE, parameterNames = {"x", "recursive"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class AnyNA extends RBuiltinNode {
+public abstract class AnyNA extends RBuiltinNode.Arg2 {
 
     private final NACheck naCheck = NACheck.create();
 
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 2d8b257bb012b72196940fe5281fd80000c11a24..b2eddad3015480640b7f423eec79d4bf52e7b15e 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
@@ -55,7 +55,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  *
  */
 @RBuiltin(name = "args", kind = INTERNAL, parameterNames = {"name"}, behavior = COMPLEX)
-public abstract class Args extends RBuiltinNode {
+public abstract class Args extends RBuiltinNode.Arg1 {
 
     @Child private GetFunctions.Get getNode;
     @Child private FrameFunctions.ParentFrame parentFrameNode;
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 9778fe9c133f131231e468e84ae808c1fe5b1d1d..9c16badfdc78a238005ca72d08897fff1d0db1c7 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
@@ -63,7 +63,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
  * TODO complete. This is sufficient for the b25 benchmark use.
  */
 @RBuiltin(name = "array", kind = INTERNAL, parameterNames = {"data", "dim", "dimnames"}, behavior = PURE)
-public abstract class Array extends RBuiltinNode {
+public abstract class Array extends RBuiltinNode.Arg3 {
 
     @Child private UpdateDimNames updateDimNames;
 
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 c374db6cb7c1214b58bd5a9a42375a049fb5798c..436d647e5b0272fb1e93448706808a897b05d80b 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "as.call", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-public abstract class AsCall extends RBuiltinNode {
+public abstract class AsCall extends RBuiltinNode.Arg1 {
 
     private final ConditionProfile nullNamesProfile = ConditionProfile.createBinaryProfile();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
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 9059814482fce42892d3fd5d1cf58400b1cf9408..f76be777345451de573b7888e29b873a5e3065d9 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
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "as.character", kind = PRIMITIVE, parameterNames = {"x", "..."}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class AsCharacter extends RBuiltinNode {
+public abstract class AsCharacter extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
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 cb0d77ec54cdb57d324a599f010f558198201e3d..d68ee4443253f69424f082d4c57cf350c764557a 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "asCharacterFactor", kind = INTERNAL, parameterNames = "x", behavior = PURE)
-public abstract class AsCharacterFactor extends RBuiltinNode {
+public abstract class AsCharacterFactor extends RBuiltinNode.Arg1 {
     private static final RStringVector CLASS_FACTOR_VEC = RDataFactory.createStringVectorFromScalar(RRuntime.CLASS_FACTOR);
 
     @Child private InheritsNode inheritsNode = InheritsNodeGen.create();
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 1ac005ce1bdee4b2298209a61c8d265f16e759e7..6ca5279ac6d762e68ca312433b6fd419f6c4b119 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 
 @RBuiltin(name = "as.complex", kind = PRIMITIVE, dispatch = RDispatch.INTERNAL_GENERIC, parameterNames = {"x", "..."}, behavior = PURE)
-public abstract class AsComplex extends RBuiltinNode {
+public abstract class AsComplex extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
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 a8e7d27ae6ef2e8fbef5317d2d217cfdc516de65..fc78a3380061c29124b906e348e6805793462ca7 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
 @RBuiltin(name = "as.double", aliases = {"as.numeric"}, kind = PRIMITIVE, parameterNames = {"x", "..."}, behavior = PURE)
-public abstract class AsDouble extends RBuiltinNode {
+public abstract class AsDouble extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
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 d3f2d8b12aa4e782cc1e5920dd07aafc85ad8eb7..d465f8dea58e6a08ff9b0403d2e1274fc47eb3b7 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
@@ -63,7 +63,7 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 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 {
+public abstract class AsFunction extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(AsFunction.class);
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 79e6144769b78e8fdfc6d8c21760ea35fa1a3197..35f09fb010d3f10bd55af458dd42335abf4ed799 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 @RBuiltin(name = "as.integer", kind = PRIMITIVE, parameterNames = {"x", "..."}, behavior = PURE)
-public abstract class AsInteger extends RBuiltinNode {
+public abstract class AsInteger extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
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 e9eb0ca41ea33b2cbf66fbcf5d871102b47cc4f2..3bdca002dea69b0a8b6be9d467be2958010d683f 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 
 @RBuiltin(name = "as.logical", kind = PRIMITIVE, parameterNames = {"x", "..."}, behavior = PURE)
-public abstract class AsLogical extends RBuiltinNode {
+public abstract class AsLogical extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
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 ef2911acc2511132e57644301ca4da9c736a415d..de58fbb3b766943aa47841bef6f4f71dea325ea8 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 
 @RBuiltin(name = "as.raw", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-public abstract class AsRaw extends RBuiltinNode {
+public abstract class AsRaw extends RBuiltinNode.Arg1 {
 
     private final ConditionProfile noAttributes = ConditionProfile.createBinaryProfile();
 
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 7a32d4cc1087628348bf70b5a6fdf9a8d788a5af..b54c737925bda0bbfdffdeb3768fc08f699e2417 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
@@ -73,7 +73,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @RBuiltin(name = "as.vector", kind = INTERNAL, parameterNames = {"x", "mode"}, dispatch = INTERNAL_GENERIC, behavior = COMPLEX)
-public abstract class AsVector extends RBuiltinNode {
+public abstract class AsVector extends RBuiltinNode.Arg2 {
 
     @Child private AsVectorInternal internal = AsVectorInternalNodeGen.create();
     @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(false, false);
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 7daef2edc8df8e010d47438a09e97acfe933537c..316c04031c5cfebdcd71e84146bfc4551d2f11aa 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
@@ -30,6 +30,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.LoopNode;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -53,7 +54,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  *
  */
 @RBuiltin(name = "assign", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "value", "envir", "inherits"}, behavior = COMPLEX)
-public abstract class Assign extends RBuiltinNode {
+public abstract class Assign extends RBuiltinNode.Arg4 {
 
     private final boolean direct;
 
@@ -65,6 +66,8 @@ public abstract class Assign extends RBuiltinNode {
         this.direct = direct;
     }
 
+    public abstract Object execute(VirtualFrame frame, RAbstractStringVector x, Object value, REnvironment pos, byte inherits);
+
     @Override
     public RBaseNode getErrorContext() {
         return direct ? this : super.getErrorContext();
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 b490525f183b60794a6fb7dbf08027efd8074869..82defa7b426037b985a828ad73ca535c01e57da3 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
@@ -46,7 +46,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment.DetachException;
 
 public class AttachFunctions {
     @RBuiltin(name = "attach", visibility = OFF, kind = INTERNAL, parameterNames = {"what", "pos", "name"}, behavior = COMPLEX)
-    public abstract static class Attach extends RBuiltinNode {
+    public abstract static class Attach extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(Attach.class);
@@ -103,7 +103,7 @@ public class AttachFunctions {
     }
 
     @RBuiltin(name = "detach", visibility = OFF, kind = INTERNAL, parameterNames = {"pos"}, behavior = COMPLEX)
-    public abstract static class Detach extends RBuiltinNode {
+    public abstract static class Detach extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Detach.class);
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 4583b8b627e416c709b28409b616ce47fae9a7dc..e746de2a76368f54daa0461ad94e6659a1f0cfd7 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
@@ -54,7 +54,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 @RBuiltin(name = "attr", kind = PRIMITIVE, parameterNames = {"x", "which", "exact"}, behavior = PURE)
-public abstract class Attr extends RBuiltinNode {
+public abstract class Attr extends RBuiltinNode.Arg3 {
 
     private final ConditionProfile searchPartialProfile = ConditionProfile.createBinaryProfile();
 
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 3c751dc9906fae8a7383ce2d6b64fc22af414917..c2e894809ced2e2442a1f0f9cb861a4604d390d7 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "attributes", kind = PRIMITIVE, parameterNames = {"obj"}, behavior = PURE)
-public abstract class Attributes extends RBuiltinNode {
+public abstract class Attributes extends RBuiltinNode.Arg1 {
 
     private final BranchProfile rownamesBranch = BranchProfile.create();
     @Child private ArrayAttributeNode arrayAttrAccess = ArrayAttributeNode.create();
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 ff6d99d9c5b390d6ff7e22ae527bdcd23cebd45c..4ee6d5194ce3f1c778d4daae7f8153523bb28902 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
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public class BaseGammaFunctions {
 
-    public abstract static class GammaBase extends RBuiltinNode {
+    public abstract static class GammaBase extends RBuiltinNode.Arg1 {
 
         private final NACheck naValCheck = NACheck.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 32498303a19d4a3ac501709c7e053f3cef7e3b98..332f4021fd4468981591d6235d62bd2d1d8ee474 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
@@ -27,7 +27,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "bincode", kind = INTERNAL, parameterNames = {"x", "breaks", "right", "include.lowest"}, behavior = PURE)
-public abstract class Bincode extends RBuiltinNode {
+public abstract class Bincode extends RBuiltinNode.Arg4 {
 
     private final NACheck naCheck = NACheck.create();
 
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 991678b692373e14f8c99492da20605eb783a5f9..1f5c1a0d158cdbd36f8675a5b8b7d4e45f625037 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
@@ -195,9 +195,9 @@ public abstract class Bind extends RBaseNode {
         boolean rowsAndColumnsNotEqual = getResultDimensions(vectors, resultDimensions, bindDims);
         RVector<?> resultVec;
         if (fromNotNullArgVector != null) {
-            resultVec = resultProfile.profile(fromNotNullArgVector.createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
+            resultVec = resultProfile.profile(vectorProfile.profile(fromNotNullArgVector).createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
         } else {
-            resultVec = resultProfile.profile(vectors[0].createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
+            resultVec = resultProfile.profile(vectorProfile.profile(vectors[0]).createEmptySameType(resultDimensions[0] * resultDimensions[1], complete));
         }
 
         if (type == BindType.cbind) {
@@ -547,7 +547,7 @@ public abstract class Bind extends RBaseNode {
         }
     }
 
-    protected abstract static class AbstractBind extends RBuiltinNode {
+    protected abstract static class AbstractBind extends RBuiltinNode.Arg2 {
         @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(false, false);
         private final ConditionProfile hasClassProfile = ConditionProfile.createBinaryProfile();
         private final ConditionProfile hasDispatchFunction = ConditionProfile.createBinaryProfile();
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 f90deab4bfdc072d82fd2d12c830743c506abdb1..5d5314d20b670a80680a6d939b2ec3c38ed0ad84 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
@@ -43,7 +43,22 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public class BitwiseFunctions {
 
-    public abstract static class BasicBitwise extends RBuiltinNode {
+    protected enum Operation {
+        AND("bitwAnd"),
+        OR("bitwOr"),
+        XOR("bitwXor"),
+        NOT("bitNot"),
+        SHIFTR("bitShiftR"),
+        SHIFTL("bitShiftL");
+
+        private final String name;
+
+        Operation(String name) {
+            this.name = name;
+        }
+    }
+
+    public abstract static class BasicBitwise extends RBuiltinNode.Arg2 {
 
         private final NACheck naCheckA = NACheck.create();
         private final NACheck naCheckB = NACheck.create();
@@ -52,21 +67,6 @@ public class BitwiseFunctions {
         @Child private TypeofNode typeofA = TypeofNodeGen.create();
         @Child private TypeofNode typeofB = TypeofNodeGen.create();
 
-        protected enum Operation {
-            AND("bitwAnd"),
-            OR("bitwOr"),
-            XOR("bitwXor"),
-            NOT("bitNot"),
-            SHIFTR("bitShiftR"),
-            SHIFTL("bitShiftL");
-
-            private final String name;
-
-            Operation(String name) {
-                this.name = name;
-            }
-        }
-
         protected Object basicBit(RAbstractIntVector aVec, RAbstractIntVector bVec, Operation op) {
             naCheckA.enable(aVec);
             naCheckB.enable(bVec);
@@ -121,14 +121,6 @@ public class BitwiseFunctions {
             return RDataFactory.createIntVector(ans, completeVector);
         }
 
-        protected Object bitNot(RAbstractIntVector aVec) {
-            int[] ans = new int[aVec.getLength()];
-            for (int i = 0; i < aVec.getLength(); i++) {
-                ans[i] = ~aVec.getDataAt(i);
-            }
-            return RDataFactory.createIntVector(ans, RDataFactory.COMPLETE_VECTOR);
-        }
-
         protected Object makeNA(int length) {
             int[] na = new int[length];
             for (int i = 0; i < length; i++) {
@@ -259,18 +251,20 @@ public class BitwiseFunctions {
     }
 
     @RBuiltin(name = "bitwiseNot", kind = INTERNAL, parameterNames = {"a"}, behavior = PURE)
-    public abstract static class BitwiseNot extends BasicBitwise {
+    public abstract static class BitwiseNot extends RBuiltinNode.Arg1 {
 
-        // @formatter:off
-    static {
-        Casts casts = new Casts(BitwiseNot.class);
+        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) {
-            return bitNot(a);
+            int[] ans = new int[a.getLength()];
+            for (int i = 0; i < a.getLength(); i++) {
+                ans[i] = ~a.getDataAt(i);
+            }
+            return RDataFactory.createIntVector(ans, RDataFactory.COMPLETE_VECTOR);
         }
     }
 }
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 47bfc87caf67c6fe2030cb4a8366922cca689058..f481242580767baacdf40fedf6f5ebfc88c71278 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = "body", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
-public abstract class Body extends RBuiltinNode {
+public abstract class Body extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(Body.class);
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 063f35a81e15e58adc3ec95b07fb2808f8361bd9..8f0f513b5c7f3caaed7217d6668f7b97b57f04ac 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,8 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-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.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
@@ -34,6 +34,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 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;
@@ -51,7 +52,7 @@ import com.oracle.truffle.r.runtime.instrument.InstrumentationState.BrowserState
 public class BrowserFunctions {
 
     @RBuiltin(name = "browser", visibility = OFF, kind = PRIMITIVE, parameterNames = {"text", "condition", "expr", "skipCalls"}, behavior = COMPLEX)
-    public abstract static class BrowserNode extends RBuiltinNode {
+    public abstract static class BrowserNode extends RBuiltinNode.Arg4 {
 
         @Child private BrowserInteractNode browserInteractNode = BrowserInteractNodeGen.create();
 
@@ -99,24 +100,21 @@ public class BrowserFunctions {
         }
     }
 
-    private abstract static class RetrieveAdapter extends RBuiltinNode {
-
-        protected static void casts(Class<? extends RetrieveAdapter> builtinClass) {
-            Casts casts = new Casts(builtinClass);
-            casts.arg("n").asIntegerVector().findFirst(0).mustBe(gt(0), Message.POSITIVE_CONTEXTS);
-        }
+    protected static void casts(Class<? extends RBuiltinNode> builtinClass) {
+        Casts casts = new Casts(builtinClass);
+        casts.arg("n").asIntegerVector().findFirst(0).mustBe(gt(0), Message.POSITIVE_CONTEXTS);
+    }
 
-        /**
-         * GnuR objects to indices <= 0 but allows positive indices that are out of range.
-         */
-        protected HelperState getHelperState(int n) {
-            BrowserState helperState = RContext.getInstance().stateInstrumentation.getBrowserState();
-            return helperState.get(n);
-        }
+    /**
+     * GnuR objects to indices <= 0 but allows positive indices that are out of range.
+     */
+    protected static HelperState getHelperState(int n) {
+        BrowserState helperState = RContext.getInstance().stateInstrumentation.getBrowserState();
+        return helperState.get(n);
     }
 
     @RBuiltin(name = "browserText", kind = INTERNAL, parameterNames = {"n"}, behavior = COMPLEX)
-    public abstract static class BrowserText extends RetrieveAdapter {
+    public abstract static class BrowserText extends RBuiltinNode.Arg1 {
 
         static {
             casts(BrowserText.class);
@@ -130,7 +128,7 @@ public class BrowserFunctions {
     }
 
     @RBuiltin(name = "browserCondition", kind = INTERNAL, parameterNames = {"n"}, behavior = COMPLEX)
-    public abstract static class BrowserCondition extends RetrieveAdapter {
+    public abstract static class BrowserCondition extends RBuiltinNode.Arg1 {
 
         static {
             casts(BrowserCondition.class);
@@ -144,7 +142,7 @@ public class BrowserFunctions {
     }
 
     @RBuiltin(name = "browserSetDebug", visibility = OFF, kind = INTERNAL, parameterNames = {"n"}, behavior = COMPLEX)
-    public abstract static class BrowserSetDebug extends RetrieveAdapter {
+    public abstract static class BrowserSetDebug extends RBuiltinNode.Arg1 {
 
         static {
             casts(BrowserSetDebug.class);
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 1cb9a9612305585f1631e746957549da5eec561f..a8223eb1e1d6ff34e2f39304d2fcb89c70f555f3 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
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "crc64", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-public abstract class CRC64 extends RBuiltinNode {
+public abstract class CRC64 extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(CRC64.class);
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 d95ff7128f3770fff7879ddaf065c0641d266c2f..53ac34d5a90d9d66c187ec8eac1ab792ff91361a 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
@@ -25,7 +25,7 @@ import com.oracle.truffle.r.runtime.context.RContext;
 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 {
+public abstract class CacheClass extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(CacheClass.class);
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 5f04839d3bd6a5603375337f7470e202b9bc4baf..20b0d7b466b80e2279f2d0fbc23cb9e5b3cf1ff4 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
@@ -57,7 +57,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  * Does not perform argument matching for first parameter "name".
  */
 @RBuiltin(name = "call", kind = PRIMITIVE, parameterNames = {"", "..."}, behavior = PURE)
-public abstract class Call extends RBuiltinNode {
+public abstract class Call extends RBuiltinNode.Arg2 {
 
     @Override
     public Object[] getDefaultParameterValues() {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Capabilities.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Capabilities.java
index b63bb9fb4ee8b1ca853fe580049c8310600be019..8a80bf7e438c3cc9ee71ec83529aebd16dbee763 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Capabilities.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Capabilities.java
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
 @RBuiltin(name = "capabilities", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-public abstract class Capabilities extends RBuiltinNode {
+public abstract class Capabilities extends RBuiltinNode.Arg0 {
     private enum Capability {
         jpeg(false, null),
         png(false, null),
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 4abee5300e9cfedfe829b1e28ed40c2c41b6ed90..a4b42e74a116a60e55c8384be8784d202d142c7b 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
@@ -63,7 +63,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
  * The {@code cat .Internal}.
  */
 @RBuiltin(name = "cat", visibility = OFF, kind = INTERNAL, parameterNames = {"arglist", "file", "sep", "fill", "labels", "append"}, behavior = IO)
-public abstract class Cat extends RBuiltinNode {
+public abstract class Cat extends RBuiltinNode.Arg6 {
 
     @Child private ToStringNode toString;
 
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 c371f39b79dc473d03089341b38d3493b60c5bc5..166b7545eaa1880ff71f7fc2e9bedd3685a70811 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
@@ -24,7 +24,7 @@ import com.oracle.truffle.r.runtime.data.RIntVector;
 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 {
+public abstract class CharMatch extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(CharMatch.class);
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 d74f7d1718600348427ac1efc5863f982926bc9b..ce3302739953a210f01e316de63d8cb28eb8e917 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  * Binomial coefficients (n, k) for real n and integral k (rounded with warning).
  */
 @RBuiltin(name = "choose", kind = INTERNAL, parameterNames = {"n", "k"}, behavior = PURE)
-public abstract class ChooseBuiltin extends RBuiltinNode {
+public abstract class ChooseBuiltin extends RBuiltinNode.Arg2 {
 
     private final NACheck na = NACheck.create();
 
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 6ceabd9a8feb8b135b21ac2f34c646a815582053..c331492d3e67f3261451005978ff2da90713c201 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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 @RBuiltin(name = "col", kind = INTERNAL, parameterNames = {"dims"}, behavior = PURE)
-public abstract class Col extends RBuiltinNode {
+public abstract class Col extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Col.class);
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 7b3b0aa1ac9ba26d092fe56ab010288e1c4ca339..b97bdbc8ffcb6060bc3979abc3558e77c7550c71 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  * specializations shared between {@link RowSums}, {@link RowMeans}, {@link ColMeans},
  * {@link RowSums}.
  */
-public abstract class ColSumsBase extends RBuiltinNode {
+public abstract class ColSumsBase extends RBuiltinNode.Arg4 {
 
     protected final NACheck na = NACheck.create();
     private final ConditionProfile vectorLengthProfile = ConditionProfile.createBinaryProfile();
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 c6eedfe8361612b3255b81e7755d00d92a0fa27e..4d4a9b0993385420ebcbc19c876ee13404a1d75c 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
@@ -70,7 +70,7 @@ abstract class ColonSpecial extends RNode {
 
 // javac fails without fully qualified name
 @com.oracle.truffle.r.runtime.builtins.RBuiltin(name = ":", kind = PRIMITIVE, parameterNames = {"", ""}, behavior = PURE)
-public abstract class Colon extends RBuiltinNode {
+public abstract class Colon extends RBuiltinNode.Arg2 {
 
     public static RNode special(ArgumentsSignature signature, RNode[] arguments, boolean inReplacement) {
         if (signature.getNonNullCount() == 0 && arguments.length == 2 && !inReplacement) {
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 54e0f519e7f44727a61ef87d554112445367f068..8e38c82231b31fd3b7cb9fafe36ecef6681a607b 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
@@ -79,7 +79,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "c", kind = PRIMITIVE, parameterNames = {"...", "recursive"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class Combine extends RBuiltinNode {
+public abstract class Combine extends RBuiltinNode.Arg2 {
 
     public static Combine create() {
         return CombineNodeGen.create();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.java
index f2ad7c85cf048e88215dbd78575d5baebe2ab7b6..9c6f24083b497de96d5c22cfa60eee2b21e33741 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CommandArgs.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,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
 @RBuiltin(name = "commandArgs", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-public abstract class CommandArgs extends RBuiltinNode {
+public abstract class CommandArgs extends RBuiltinNode.Arg0 {
 
     @Specialization
     @TruffleBoundary
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 7fb2b3ce4d4c9c558cda43fd5bff4ff849c9a436..515a446f104eff8d27cd9562b20f4507c3a0e4ba 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
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 public class CompileFunctions {
     @RBuiltin(name = "compilePKGS", kind = INTERNAL, parameterNames = "enable", behavior = PURE)
-    public abstract static class CompilePKGS extends RBuiltinNode {
+    public abstract static class CompilePKGS extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(CompilePKGS.class);
@@ -49,7 +49,7 @@ public class CompileFunctions {
     }
 
     @RBuiltin(name = "enableJIT", kind = INTERNAL, parameterNames = "level", behavior = PURE)
-    public abstract static class EnableJIT extends RBuiltinNode {
+    public abstract static class EnableJIT extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(EnableJIT.class);
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 d79675c6367d2c6c0a0f9827c6018ce6224f17c9..2034744f3a4871d87cb00d21174b0bf48838ff73 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 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 {
+public abstract class Complex extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(Complex.class);
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 1c65b8139a2f3e7630b50c7a8652da2410a3fe50..12fffb616a49f19672854e6aa2d57c0c22326559 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
@@ -28,7 +28,6 @@ import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.VirtualFrame;
 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.runtime.RError;
 import com.oracle.truffle.r.runtime.RErrorHandling;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -43,20 +42,8 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  */
 public class ConditionFunctions {
 
-    public abstract static class EvalAdapter extends RBuiltinNode {
-        @Child private PromiseHelperNode promiseHelper;
-
-        protected PromiseHelperNode initPromiseHelper() {
-            if (promiseHelper == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                promiseHelper = insert(new PromiseHelperNode());
-            }
-            return promiseHelper;
-        }
-    }
-
     @RBuiltin(name = ".addCondHands", visibility = OFF, kind = INTERNAL, parameterNames = {"classes", "handlers", "parentenv", "target", "calling"}, behavior = COMPLEX)
-    public abstract static class AddCondHands extends RBuiltinNode {
+    public abstract static class AddCondHands extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(AddCondHands.class);
@@ -100,7 +87,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = ".resetCondHands", visibility = OFF, kind = INTERNAL, parameterNames = {"stack"}, behavior = COMPLEX)
-    public abstract static class ResetCondHands extends RBuiltinNode {
+    public abstract static class ResetCondHands extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(ResetCondHands.class);
@@ -114,24 +101,12 @@ public class ConditionFunctions {
         }
     }
 
-    public abstract static class RestartAdapter extends RBuiltinNode {
-        protected void checkLength(RList restart) {
-            if (restart.getLength() < 2) {
-                throw error(RError.Message.BAD_RESTART);
-            }
-        }
-
-        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 {
+    public abstract static class AddRestart extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(AddRestart.class);
-            restart(casts);
+            casts.arg("restart").mustBe(instanceOf(RList.class), RError.Message.BAD_RESTART);
         }
 
         protected FrameSlot createRestartFrameSlot(VirtualFrame frame) {
@@ -141,7 +116,9 @@ public class ConditionFunctions {
         @Specialization
         protected Object addRestart(VirtualFrame frame, RList restart,
                         @Cached("createRestartFrameSlot(frame)") FrameSlot restartFrameSlot) {
-            checkLength(restart);
+            if (restart.getLength() < 2) {
+                throw error(RError.Message.BAD_RESTART);
+            }
             try {
                 if (!frame.isObject(restartFrameSlot) || frame.getObject(restartFrameSlot) == null) {
                     frame.setObject(restartFrameSlot, RErrorHandling.getRestartStack());
@@ -155,7 +132,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = ".getRestart", kind = INTERNAL, parameterNames = "restart", behavior = COMPLEX)
-    public abstract static class GetRestart extends RBuiltinNode {
+    public abstract static class GetRestart extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(GetRestart.class);
@@ -170,17 +147,19 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = ".invokeRestart", kind = INTERNAL, parameterNames = {"restart", "args"}, behavior = COMPLEX)
-    public abstract static class InvokeRestart extends RestartAdapter {
+    public abstract static class InvokeRestart extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(InvokeRestart.class);
-            restart(casts);
+            casts.arg("restart").mustBe(instanceOf(RList.class), RError.Message.BAD_RESTART);
         }
 
         @Specialization
         @TruffleBoundary
         protected RNull invokeRestart(RList restart, Object args) {
-            checkLength(restart);
+            if (restart.getLength() < 2) {
+                throw error(RError.Message.BAD_RESTART);
+            }
             RErrorHandling.invokeRestart(restart, args);
             // invokeRestart is expected to always return via a ReturnException
             throw error(RError.Message.RESTART_NOT_ON_STACK);
@@ -188,7 +167,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = ".signalCondition", kind = INTERNAL, parameterNames = {"condition", "msg", "call"}, behavior = COMPLEX)
-    public abstract static class SignalCondition extends RBuiltinNode {
+    public abstract static class SignalCondition extends RBuiltinNode.Arg3 {
 
         static {
             Casts.noCasts(SignalCondition.class);
@@ -202,7 +181,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = "geterrmessage", kind = INTERNAL, parameterNames = {}, behavior = COMPLEX)
-    public abstract static class Geterrmessage extends RBuiltinNode {
+    public abstract static class Geterrmessage extends RBuiltinNode.Arg0 {
         @Specialization
         protected String geterrmessage() {
             return RErrorHandling.geterrmessage();
@@ -210,7 +189,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = "seterrmessage", visibility = OFF, kind = INTERNAL, parameterNames = "msg", behavior = COMPLEX)
-    public abstract static class Seterrmessage extends RBuiltinNode {
+    public abstract static class Seterrmessage extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Seterrmessage.class);
@@ -225,7 +204,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = ".dfltWarn", kind = INTERNAL, parameterNames = {"message", "call"}, behavior = COMPLEX)
-    public abstract static class DfltWarn extends RBuiltinNode {
+    public abstract static class DfltWarn extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(DfltWarn.class);
@@ -240,7 +219,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = ".dfltStop", kind = INTERNAL, parameterNames = {"message", "call"}, behavior = COMPLEX)
-    public abstract static class DfltStop extends RBuiltinNode {
+    public abstract static class DfltStop extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(DfltStop.class);
@@ -255,7 +234,7 @@ public class ConditionFunctions {
     }
 
     @RBuiltin(name = "printDeferredWarnings", visibility = OFF, kind = INTERNAL, parameterNames = {}, behavior = COMPLEX)
-    public abstract static class PrintDeferredWarnings extends RBuiltinNode {
+    public abstract static class PrintDeferredWarnings extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected RNull printDeferredWarnings() {
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 efa1508a885e78f80440a7edcb17f481b1448259..976df1b8bdfcc31b5c44f41c1c6c90e1ebc398e7 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
@@ -125,7 +125,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  */
 public abstract class ConnectionFunctions {
     @RBuiltin(name = "stdin", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class Stdin extends RBuiltinNode {
+    public abstract static class Stdin extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected RAbstractIntVector stdin() {
@@ -134,7 +134,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "stdout", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class Stdout extends RBuiltinNode {
+    public abstract static class Stdout extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected RAbstractIntVector stdout() {
@@ -143,7 +143,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "stderr", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class Stderr extends RBuiltinNode {
+    public abstract static class Stderr extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected RAbstractIntVector stderr() {
@@ -219,7 +219,7 @@ 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 {
+    public abstract static class File extends RBuiltinNode.Arg6 {
 
         static {
             Casts casts = new Casts(File.class);
@@ -279,7 +279,7 @@ public abstract class ConnectionFunctions {
      * uncompressed files, and files compressed by {@code bzip2, xz, lzma}.
      */
 
-    public abstract static class ZZFileAdapter extends RBuiltinNode {
+    public abstract static class ZZFileAdapter extends RBuiltinNode.Arg4 {
         private final RCompression.Type cType;
 
         protected ZZFileAdapter(RCompression.Type cType) {
@@ -347,7 +347,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "textConnection", kind = INTERNAL, parameterNames = {"description", "text", "open", "env", "encoding"}, behavior = IO)
-    public abstract static class TextConnection extends RBuiltinNode {
+    public abstract static class TextConnection extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(TextConnection.class);
@@ -375,7 +375,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "textConnectionValue", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
-    public abstract static class TextConnectionValue extends RBuiltinNode {
+    public abstract static class TextConnectionValue extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(TextConnectionValue.class);
@@ -395,7 +395,7 @@ 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 {
+    public abstract static class SocketConnection extends RBuiltinNode.Arg7 {
 
         static {
             Casts casts = new Casts(SocketConnection.class);
@@ -422,7 +422,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "url", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding", "method"}, behavior = IO)
-    public abstract static class URLConnection extends RBuiltinNode {
+    public abstract static class URLConnection extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(URLConnection.class);
@@ -450,7 +450,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "rawConnection", kind = INTERNAL, parameterNames = {"description", "object", "open"}, behavior = IO)
-    public abstract static class RawConnection extends RBuiltinNode {
+    public abstract static class RawConnection extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(RawConnection.class);
@@ -481,7 +481,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "rawConnectionValue", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
-    public abstract static class RawConnectionValue extends RBuiltinNode {
+    public abstract static class RawConnectionValue extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(RawConnectionValue.class);
@@ -501,7 +501,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "summary.connection", kind = INTERNAL, parameterNames = {"object"}, behavior = IO)
-    public abstract static class Summary extends RBuiltinNode {
+    public abstract static class Summary extends RBuiltinNode.Arg1 {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"description", "class", "mode", "text", "opened", "can read", "can write"},
                         RDataFactory.COMPLETE_VECTOR);
 
@@ -527,7 +527,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "open", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "open", "blocking"}, behavior = IO)
-    public abstract static class Open extends RBuiltinNode {
+    public abstract static class Open extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(Open.class);
@@ -556,7 +556,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "isOpen", kind = INTERNAL, parameterNames = {"con", "rw"}, behavior = IO)
-    public abstract static class IsOpen extends RBuiltinNode {
+    public abstract static class IsOpen extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(IsOpen.class);
@@ -586,7 +586,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "close", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "type"}, behavior = IO)
-    public abstract static class Close extends RBuiltinNode {
+    public abstract static class Close extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(Close.class);
@@ -608,7 +608,7 @@ 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 {
+    public abstract static class ReadLines extends RBuiltinNode.Arg6 {
 
         static {
             Casts casts = new Casts(ReadLines.class);
@@ -637,7 +637,7 @@ 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 {
+    public abstract static class WriteLines extends RBuiltinNode.Arg4 {
 
         static {
             Casts casts = new Casts(WriteLines.class);
@@ -660,7 +660,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "flush", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
-    public abstract static class Flush extends RBuiltinNode {
+    public abstract static class Flush extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Flush.class);
@@ -680,7 +680,7 @@ 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 {
+    public abstract static class PushBack extends RBuiltinNode.Arg4 {
 
         static {
             Casts casts = new Casts(PushBack.class);
@@ -699,7 +699,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "pushBackLength", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
-    public abstract static class PushBackLength extends RBuiltinNode {
+    public abstract static class PushBackLength extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(PushBackLength.class);
@@ -713,7 +713,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "clearPushBack", visibility = OFF, kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
-    public abstract static class PushBackClear extends RBuiltinNode {
+    public abstract static class PushBackClear extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(PushBackClear.class);
@@ -728,7 +728,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "readChar", kind = INTERNAL, parameterNames = {"con", "nchars", "useBytes"}, behavior = IO)
-    public abstract static class ReadChar extends RBuiltinNode {
+    public abstract static class ReadChar extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(ReadChar.class);
@@ -763,7 +763,7 @@ 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 {
+    public abstract static class WriteChar extends RBuiltinNode.Arg5 {
 
         static {
             // @formatter:off
@@ -832,7 +832,7 @@ 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 {
+    public abstract static class ReadBin extends RBuiltinNode.Arg6 {
 
         static {
             Casts casts = new Casts(ReadBin.class);
@@ -1124,7 +1124,7 @@ 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 {
+    public abstract static class WriteBin extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(WriteBin.class);
@@ -1168,7 +1168,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "getConnection", kind = INTERNAL, parameterNames = {"what"}, behavior = IO)
-    public abstract static class GetConnection extends RBuiltinNode {
+    public abstract static class GetConnection extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(GetConnection.class);
@@ -1188,7 +1188,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "getAllConnections", kind = INTERNAL, parameterNames = {}, behavior = IO)
-    public abstract static class GetAllConnections extends RBuiltinNode {
+    public abstract static class GetAllConnections extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected RAbstractIntVector getAllConnections() {
@@ -1197,7 +1197,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "isSeekable", kind = INTERNAL, parameterNames = "con", behavior = IO)
-    public abstract static class IsSeekable extends RBuiltinNode {
+    public abstract static class IsSeekable extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(IsSeekable.class);
@@ -1212,7 +1212,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "seek", kind = INTERNAL, parameterNames = {"con", "where", "origin", "rw"}, behavior = IO)
-    public abstract static class Seek extends RBuiltinNode {
+    public abstract static class Seek extends RBuiltinNode.Arg4 {
 
         static {
             Casts casts = new Casts(Seek.class);
@@ -1250,7 +1250,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "fifo", kind = INTERNAL, parameterNames = {"description", "open", "blocking", "encoding"}, behavior = IO)
-    public abstract static class Fifo extends RBuiltinNode {
+    public abstract static class Fifo extends RBuiltinNode.Arg4 {
 
         static {
             Casts casts = new Casts(Fifo.class);
@@ -1279,7 +1279,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "pipe", kind = INTERNAL, parameterNames = {"description", "open", "encoding"}, behavior = IO)
-    public abstract static class Pipe extends RBuiltinNode {
+    public abstract static class Pipe extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(Pipe.class);
@@ -1305,7 +1305,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "isIncomplete", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
-    public abstract static class IsIncomplete extends RBuiltinNode {
+    public abstract static class IsIncomplete extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(IsIncomplete.class);
@@ -1322,7 +1322,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = "truncate", kind = INTERNAL, parameterNames = {"con"}, behavior = IO)
-    public abstract static class Truncate extends RBuiltinNode {
+    public abstract static class Truncate extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Truncate.class);
@@ -1343,7 +1343,7 @@ public abstract class ConnectionFunctions {
     }
 
     @RBuiltin(name = ".fastr.channelConnection", kind = RBuiltinKind.PRIMITIVE, parameterNames = {"channel", "open", "encoding"}, behavior = IO)
-    public abstract static class ChannelConnection extends RBuiltinNode {
+    public abstract static class ChannelConnection extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(ChannelConnection.class);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Contributors.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Contributors.java
index 2a64ec2f8e66d713c09c10b61e77a553d0e9a9fb..bb5c8b3413621ec937669ee560ec014b0b8d7eba 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Contributors.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Contributors.java
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.conn.StdConnections;
 import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = "contributors", visibility = OFF, kind = SUBSTITUTE, parameterNames = {}, behavior = IO)
-public abstract class Contributors extends RBuiltinNode {
+public abstract class Contributors extends RBuiltinNode.Arg0 {
 
     private static final String CONTRIBUTORS = Utils.getResourceAsString(Contributors.class, "CONTRIBUTORS", true);
 
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 d9f2875e1ccb591a09aae6c1cad02f67cb05d411..e3080d28c883bfb42d704b2c7a3ef5ab1f3346b6 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "copyDFattr", kind = INTERNAL, parameterNames = {"", ""}, behavior = COMPLEX)
-public abstract class CopyDFAttr extends RBuiltinNode {
+public abstract class CopyDFAttr extends RBuiltinNode.Arg2 {
 
     static {
         Casts.noCasts(CopyDFAttr.class);
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 4928c3ee38ddfc53a9928611b28e7d35bf97fc12..56ddfda61520b9138b849c9a25584ee683956452 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "crossprod", kind = INTERNAL, parameterNames = {"x", "y"}, behavior = PURE)
-public abstract class Crossprod extends RBuiltinNode {
+public abstract class Crossprod extends RBuiltinNode.Arg2 {
 
     @Child private MatMult matMult = MatMultNodeGen.create(/* promoteDimNames: */ false);
     @Child private Transpose transpose;
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 b108f85ee465ed215bea73533cc4a3cd3f0ea057..b21e15c0bcfccc12fd6186f06637d87390850e3c 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "cummax", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-public abstract class CumMax extends RBuiltinNode {
+public abstract class CumMax extends RBuiltinNode.Arg1 {
 
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
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 fe0440255665e0a9d5e6f4cf155e46393b4a8ff8..c558b2df55593104dfa129c01f52fedb1118e3a6 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "cummin", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-public abstract class CumMin extends RBuiltinNode {
+public abstract class CumMin extends RBuiltinNode.Arg1 {
 
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
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 50a2f53a3b06f262042426071024786e9ed98d41..69767d4e3dd9bf4cd91cdf9c527a677e1d101a19 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "cumprod", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-public abstract class CumProd extends RBuiltinNode {
+public abstract class CumProd extends RBuiltinNode.Arg1 {
 
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
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 d0aa7107981d5d6d162c5e402c75013241dcd971..683d2b46ad780a6b3ca3e1e7e2d6035ac4ca1ba8 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
@@ -57,7 +57,7 @@ import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "cumsum", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-public abstract class CumSum extends RBuiltinNode {
+public abstract class CumSum extends RBuiltinNode.Arg1 {
 
     private final NACheck na = NACheck.create();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
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 1a1f3585998b8811d09a2c1013491b7a3678b01a..d0361a493fd9fba3da09709a9e967e9334354574 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.conn.RConnection;
  * The {@code dput .Internal}.
  */
 @RBuiltin(name = "dput", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "file", "opts"}, behavior = IO)
-public abstract class DPut extends RBuiltinNode {
+public abstract class DPut extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(DPut.class);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Date.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Date.java
index 2fc9b6f40b7db921f916333bc7eccc64a093de02..cbf8371eec4c2a499a19820663d0b060724adda7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Date.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Date.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,7 +23,7 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "date", kind = INTERNAL, parameterNames = {}, behavior = IO)
-public abstract class Date extends RBuiltinNode {
+public abstract class Date extends RBuiltinNode.Arg0 {
 
     @Specialization
     @TruffleBoundary
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 f63bcc40cca8afb779688317d52297f773cffa4a..963a91850bce768380aa729a5abe1be9d79a090d 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
@@ -137,7 +137,7 @@ public class DatePOSIXFunctions {
     }
 
     @RBuiltin(name = "Date2POSIXlt", kind = INTERNAL, parameterNames = "x", behavior = PURE)
-    public abstract static class Date2POSIXlt extends RBuiltinNode {
+    public abstract static class Date2POSIXlt extends RBuiltinNode.Arg1 {
 
         @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
@@ -173,7 +173,7 @@ public class DatePOSIXFunctions {
     }
 
     @RBuiltin(name = "as.POSIXlt", kind = INTERNAL, parameterNames = {"x", "tz"}, behavior = READS_STATE)
-    public abstract static class AsPOSIXlt extends RBuiltinNode {
+    public abstract static class AsPOSIXlt extends RBuiltinNode.Arg2 {
 
         @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
@@ -215,7 +215,7 @@ public class DatePOSIXFunctions {
     }
 
     @RBuiltin(name = "as.POSIXct", kind = INTERNAL, parameterNames = {"x", "tz"}, behavior = READS_STATE)
-    public abstract static class AsPOSIXct extends RBuiltinNode {
+    public abstract static class AsPOSIXct extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(AsPOSIXct.class);
@@ -273,7 +273,7 @@ public class DatePOSIXFunctions {
     }
 
     @RBuiltin(name = "POSIXlt2Date", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class POSIXlt2Date extends RBuiltinNode {
+    public abstract static class POSIXlt2Date extends RBuiltinNode.Arg1 {
         private static final RStringVector CLASS_ATTR = (RStringVector) RDataFactory.createStringVectorFromScalar("Date").makeSharedPermanent();
 
         static {
@@ -324,7 +324,7 @@ public class DatePOSIXFunctions {
     }
 
     @RBuiltin(name = "format.POSIXlt", kind = INTERNAL, parameterNames = {"x", "format", "usetz"}, behavior = READS_STATE)
-    public abstract static class FormatPOSIXlt extends RBuiltinNode {
+    public abstract static class FormatPOSIXlt extends RBuiltinNode.Arg3 {
 
         private static final HashMap<String, String> TIME_ZONE_MAPPING = new HashMap<>();
 
@@ -390,7 +390,7 @@ public class DatePOSIXFunctions {
     }
 
     @RBuiltin(name = "strptime", kind = INTERNAL, parameterNames = {"x", "format", "tz"}, behavior = PURE)
-    public abstract static class StrPTime extends RBuiltinNode {
+    public abstract static class StrPTime extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(StrPTime.class);
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 6ed51005c69664a72cb70b748391edbf0165e524..e0793ec5a6f9c87c4c6219f5a5909bd74dcb78c1 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
@@ -29,6 +29,7 @@ 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.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.helpers.DebugHandling;
 import com.oracle.truffle.r.runtime.RError;
@@ -37,29 +38,27 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 public class DebugFunctions {
 
-    protected abstract static class ErrorAndFunAdapter extends RBuiltinNode {
-
-        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 static Casts createCasts(Class<? extends RBuiltinNode> 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 {
-            // GnuR does not generate an error for builtins, but debug (obviously) has no effect
-            if (!fun.isBuiltin()) {
-                if (!DebugHandling.enableDebug(fun, text, condition, once, false)) {
-                    throw error(RError.Message.GENERIC, "failed to attach debug handler (not instrumented?)");
-                }
+    protected static void doDebug(RBaseNode node, RFunction fun, Object text, Object condition, boolean once) throws RError {
+        // GnuR does not generate an error for builtins, but debug (obviously) has no effect
+        if (!fun.isBuiltin()) {
+            if (!DebugHandling.enableDebug(fun, text, condition, once, false)) {
+                throw node.error(RError.Message.GENERIC, "failed to attach debug handler (not instrumented?)");
             }
         }
     }
 
     @RBuiltin(name = "debug", visibility = OFF, kind = INTERNAL, parameterNames = {"fun", "text", "condition"}, behavior = COMPLEX)
-    public abstract static class Debug extends ErrorAndFunAdapter {
+    public abstract static class Debug extends RBuiltinNode.Arg3 {
 
         static {
             createCasts(Debug.class);
@@ -67,14 +66,14 @@ public class DebugFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected RNull doDebug(RFunction fun, Object text, Object condition) {
-            doDebug(fun, text, condition, false);
+        protected RNull debug(RFunction fun, Object text, Object condition) {
+            doDebug(this, fun, text, condition, false);
             return RNull.instance;
         }
     }
 
     @RBuiltin(name = "debugonce", visibility = OFF, kind = INTERNAL, parameterNames = {"fun", "text", "condition"}, behavior = COMPLEX)
-    public abstract static class DebugOnce extends ErrorAndFunAdapter {
+    public abstract static class DebugOnce extends RBuiltinNode.Arg3 {
 
         static {
             createCasts(DebugOnce.class);
@@ -84,13 +83,13 @@ public class DebugFunctions {
         @TruffleBoundary
         protected RNull debugonce(RFunction fun, Object text, Object condition) {
             // TODO implement
-            doDebug(fun, text, condition, true);
+            doDebug(this, fun, text, condition, true);
             return RNull.instance;
         }
     }
 
     @RBuiltin(name = "undebug", visibility = OFF, kind = INTERNAL, parameterNames = {"fun"}, behavior = COMPLEX)
-    public abstract static class UnDebug extends ErrorAndFunAdapter {
+    public abstract static class UnDebug extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(UnDebug.class);
@@ -107,7 +106,7 @@ public class DebugFunctions {
     }
 
     @RBuiltin(name = "isdebugged", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
-    public abstract static class IsDebugged extends ErrorAndFunAdapter {
+    public abstract static class IsDebugged extends RBuiltinNode.Arg1 {
 
         static {
             createCasts(IsDebugged.class);
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 41271c43eaee16ff9d4a6a1947ea7352893905a9..d62180268e2533f72a3793fda7ca1a97160fa8ba 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
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
 
 @RBuiltin(name = "delayedAssign", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "value", "eval.env", "assign.env"}, behavior = COMPLEX)
-public abstract class DelayedAssign extends RBuiltinNode {
+public abstract class DelayedAssign extends RBuiltinNode.Arg4 {
 
     static {
         Casts casts = new Casts(DelayedAssign.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 c00c28bee40170c2589b18ddc8de537d456450ee..fdd7a26615bc8c8b22a40276dca4f24dcdb20cc5 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
@@ -28,7 +28,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 // Part of this transcribed from GnuR src/main/deparse.c
 
 @RBuiltin(name = "deparse", kind = INTERNAL, parameterNames = {"expr", "width.cutoff", "backtick", "control", "nlines"}, behavior = PURE)
-public abstract class Deparse extends RBuiltinNode {
+public abstract class Deparse extends RBuiltinNode.Arg5 {
 
     static {
         Casts casts = new Casts(Deparse.class);
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 c9c2b803af3b6cbd079e9b80ab3b60d0a6905e06..6d2ba76bcbd4cf034911c7e9525383cdb0ec0837 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 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 {
+public abstract class Diag extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(Diag.class);
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 9e495172e5ddfa9b633c73da7eaff65ecf8fc582..ddc5113be3b33991db30d9ba4f01053a0b68fed8 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 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 {
+public abstract class Dim extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(Dim.class);
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 2993a023e58813ab9b89c0b08244068e5eaf09ad..bcbd242272dbcbce9ae91088c65459cad906e17b 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 
 @RBuiltin(name = "dimnames", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class DimNames extends RBuiltinNode {
+public abstract class DimNames extends RBuiltinNode.Arg1 {
 
     private final ConditionProfile nullProfile = ConditionProfile.createBinaryProfile();
 
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 a9ae510c24bd0cf53c3a0eba9d7d998f43a2aa22..ec10b5b52c2799325428a28f97b2791f025321dd 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
@@ -67,7 +67,7 @@ import com.oracle.truffle.r.runtime.nodes.InternalRSyntaxNodeChildren;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 @RBuiltin(name = ".fastr.do.call", visibility = CUSTOM, kind = RBuiltinKind.INTERNAL, parameterNames = {"what", "args", "quote", "envir"}, behavior = COMPLEX)
-public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNodeChildren {
+public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSyntaxNodeChildren {
 
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
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 295782ffeddd39e036218c3ec8828e504f35691d..c326691292d80b7c9e1ca3af7aac3af91323645a 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
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "drop", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-public abstract class Drop extends RBuiltinNode {
+public abstract class Drop extends RBuiltinNode.Arg1 {
 
     private final ConditionProfile nullDimensions = ConditionProfile.createBinaryProfile();
     private final ConditionProfile resultIsVector = ConditionProfile.createBinaryProfile();
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 b2043833e9b8aba49aa80c5754981b8d8cbbd395..dface54eb35148396b1b38cf1e18f7587b918e4d 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
@@ -16,8 +16,8 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyList;
 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.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.binary.CastTypeNode;
@@ -32,18 +32,14 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 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.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.DuplicationHelper;
 
 public class DuplicatedFunctions {
 
-    protected abstract static class Adapter extends RBuiltinNode {
-        @Child protected CastTypeNode castTypeNode;
-        @Child protected TypeofNode typeof;
-
-        private final ConditionProfile incomparable = ConditionProfile.createBinaryProfile();
+    @RBuiltin(name = "duplicated", kind = INTERNAL, parameterNames = {"x", "incomparables", "fromLast", "nmax"}, behavior = PURE)
+    public abstract static class Duplicated extends RBuiltinNode.Arg4 {
 
         protected static void casts(Casts casts) {
             // these are similar to those in DuplicatedFunctions.java
@@ -54,37 +50,6 @@ public class DuplicatedFunctions {
             casts.arg("fromLast").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE);
         }
 
-        protected boolean isIncomparable(RAbstractVector incomparables) {
-            if (incomparable.profile(incomparables.getLength() == 1 && incomparables instanceof RLogicalVector && ((RAbstractLogicalVector) incomparables).getDataAt(0) == RRuntime.LOGICAL_FALSE)) {
-                return false;
-            } else {
-                return true;
-            }
-        }
-
-        protected boolean notAbstractVector(Object o) {
-            return !(o instanceof RAbstractVector);
-        }
-
-        protected boolean empty(RAbstractContainer x) {
-            return x.getLength() == 0;
-        }
-
-        protected void initChildren() {
-            if (castTypeNode == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                castTypeNode = insert(CastTypeNodeGen.create(null, null));
-            }
-            if (typeof == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                typeof = insert(TypeofNodeGen.create());
-            }
-        }
-    }
-
-    @RBuiltin(name = "duplicated", kind = INTERNAL, parameterNames = {"x", "incomparables", "fromLast", "nmax"}, behavior = PURE)
-    public abstract static class Duplicated extends Adapter {
-
         static {
             Casts casts = new Casts(Duplicated.class);
             casts(casts);
@@ -93,29 +58,48 @@ public class DuplicatedFunctions {
             casts.arg("nmax").asIntegerVector().findFirst(RRuntime.INT_NA);
         }
 
+        private final ConditionProfile incomparable = ConditionProfile.createBinaryProfile();
+
+        protected boolean isIncomparable(RAbstractVector incomparables) {
+            if (incomparable.profile(incomparables.getLength() == 1 && incomparables instanceof RLogicalVector && ((RAbstractLogicalVector) incomparables).getDataAt(0) == RRuntime.LOGICAL_FALSE)) {
+                return false;
+            } else {
+                return true;
+            }
+        }
+
         @TruffleBoundary
         protected static RLogicalVector analyzeAndCreateResult(RAbstractVector x, RAbstractVector incomparables, byte fromLast) {
             DuplicationHelper ds = DuplicationHelper.analyze(x, incomparables, false, RRuntime.fromLogical(fromLast));
             return RDataFactory.createLogicalVector(ds.getDupVec(), RDataFactory.COMPLETE_VECTOR);
         }
 
-        @Specialization(guards = {"!isIncomparable(incomparables)", "!empty(x)"})
+        @Specialization(guards = {"!isIncomparable(incomparables)", "x.getLength() != 0"})
         protected RLogicalVector duplicatedFalseIncomparables(RAbstractVector x, @SuppressWarnings("unused") RAbstractVector incomparables, byte fromLast, @SuppressWarnings("unused") int nmax) {
             return analyzeAndCreateResult(x, null, fromLast);
         }
 
-        @Specialization(guards = {"isIncomparable(incomparables)", "!empty(x)"})
-        protected RLogicalVector duplicatedTrueIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast, @SuppressWarnings("unused") int nmax) {
-            initChildren();
+        protected static TypeofNode createTypeof() {
+            return TypeofNodeGen.create();
+        }
+
+        protected static CastTypeNode createCastType() {
+            return CastTypeNodeGen.create();
+        }
+
+        @Specialization(guards = {"isIncomparable(incomparables)", "x.getLength() != 0"})
+        protected RLogicalVector duplicatedTrueIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast, @SuppressWarnings("unused") int nmax,
+                        @Cached("createTypeof()") TypeofNode typeof,
+                        @Cached("createCastType()") CastTypeNode castTypeNode) {
             RType xType = typeof.execute(x);
             RAbstractVector vector = (RAbstractVector) (castTypeNode.execute(incomparables, xType));
             return analyzeAndCreateResult(x, vector, fromLast);
         }
 
         @SuppressWarnings("unused")
-        @Specialization(guards = {"notAbstractVector(incomparables)", "!empty(x)"})
-        protected RLogicalVector duplicatedTrueIncomparables(RAbstractVector x, Object incomparables, byte fromLast, int nmax) {
-            initChildren();
+        @Specialization(guards = {"!isRAbstractVector(incomparables)", "x.getLength() != 0"})
+        protected RLogicalVector duplicatedTrueIncomparables(RAbstractVector x, Object incomparables, byte fromLast, int nmax,
+                        @Cached("createTypeof()") TypeofNode typeof) {
             RType xType = typeof.execute(x);
             // TODO: this is not quite correct, as passing expression generated some obscure error
             // message, but is it worth fixing
@@ -123,44 +107,62 @@ public class DuplicatedFunctions {
         }
 
         @SuppressWarnings("unused")
-        @Specialization(guards = "empty(x)")
+        @Specialization(guards = "x.getLength() == 0")
         protected RLogicalVector duplicatedEmpty(RAbstractVector x, Object incomparables, byte fromLast, int nmax) {
             return RDataFactory.createEmptyLogicalVector();
         }
     }
 
     @RBuiltin(name = "anyDuplicated", kind = INTERNAL, parameterNames = {"x", "incomparables", "fromLast"}, behavior = PURE)
-    public abstract static class AnyDuplicated extends Adapter {
+    public abstract static class AnyDuplicated extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(AnyDuplicated.class);
-            casts(casts);
+            Duplicated.casts(casts);
+        }
+
+        private final ConditionProfile incomparable = ConditionProfile.createBinaryProfile();
+
+        protected boolean isIncomparable(RAbstractVector incomparables) {
+            if (incomparable.profile(incomparables.getLength() == 1 && incomparables instanceof RLogicalVector && ((RAbstractLogicalVector) incomparables).getDataAt(0) == RRuntime.LOGICAL_FALSE)) {
+                return false;
+            } else {
+                return true;
+            }
         }
 
         @SuppressWarnings("unused")
-        @Specialization(guards = {"!isIncomparable(incomparables)", "!empty(x)"})
+        @Specialization(guards = {"!isIncomparable(incomparables)", "x.getLength() != 0"})
         protected int anyDuplicatedFalseIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast) {
             return DuplicationHelper.analyze(x, null, true, RRuntime.fromLogical(fromLast)).getIndex();
         }
 
-        @Specialization(guards = {"isIncomparable(incomparables)", "!empty(x)"})
-        protected int anyDuplicatedTrueIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast) {
-            initChildren();
+        protected static TypeofNode createTypeof() {
+            return TypeofNodeGen.create();
+        }
+
+        protected static CastTypeNode createCastType() {
+            return CastTypeNodeGen.create();
+        }
+
+        @Specialization(guards = {"isIncomparable(incomparables)", "x.getLength() != 0"})
+        protected int anyDuplicatedTrueIncomparables(RAbstractVector x, RAbstractVector incomparables, byte fromLast,
+                        @Cached("createTypeof()") TypeofNode typeof,
+                        @Cached("createCastType()") CastTypeNode castTypeNode) {
             RType xType = typeof.execute(x);
             return DuplicationHelper.analyze(x, (RAbstractVector) (castTypeNode.execute(incomparables, xType)), true, RRuntime.fromLogical(fromLast)).getIndex();
         }
 
-        @Specialization(guards = {"notAbstractVector(incomparables)", "!empty(x)"})
+        @Specialization(guards = {"!isRAbstractVector(incomparables)", "x.getLength() != 0"})
         @TruffleBoundary
         protected int anyDuplicatedTrueIncomparables(RAbstractVector x, Object incomparables, @SuppressWarnings("unused") byte fromLast) {
-            initChildren();
             // TODO: this is not quite correct, as passing expression generated some obscure error
             // message, but is it worth fixing
             throw error(RError.Message.CANNOT_COERCE, TypeofNode.getTypeof(incomparables).getName(), TypeofNode.getTypeof(x).getName());
         }
 
         @SuppressWarnings("unused")
-        @Specialization(guards = "empty(x)")
+        @Specialization(guards = "x.getLength() == 0")
         protected int anyDuplicatedEmpty(RAbstractVector x, Object incomparables, byte fromLast) {
             return 0;
         }
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 535ada9f477e56120a32730edb61e2af76540627..1156a95d30ae2872f2e2c89d9a130509b324f968 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
@@ -58,7 +58,7 @@ public class DynLoadFunctions {
     private static final String DLLINFOLIST_CLASS = "DLLInfoList";
 
     @RBuiltin(name = "dyn.load", visibility = OFF, kind = INTERNAL, parameterNames = {"lib", "local", "now", "unused"}, behavior = COMPLEX)
-    public abstract static class DynLoad extends RBuiltinNode {
+    public abstract static class DynLoad extends RBuiltinNode.Arg4 {
         @Child private DLL.LoadPackageDLLNode loadPackageDLLNode = DLL.LoadPackageDLLNode.create();
 
         static {
@@ -82,7 +82,7 @@ public class DynLoadFunctions {
     }
 
     @RBuiltin(name = "dyn.unload", visibility = OFF, kind = INTERNAL, parameterNames = {"lib"}, behavior = COMPLEX)
-    public abstract static class DynUnload extends RBuiltinNode {
+    public abstract static class DynUnload extends RBuiltinNode.Arg1 {
         @Child DLL.UnloadNode dllUnloadNode = DLL.UnloadNode.create();
 
         static {
@@ -103,7 +103,7 @@ public class DynLoadFunctions {
     }
 
     @RBuiltin(name = "getLoadedDLLs", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class GetLoadedDLLs extends RBuiltinNode {
+    public abstract static class GetLoadedDLLs extends RBuiltinNode.Arg0 {
 
         @Child private SetClassAttributeNode setClassAttrNode = SetClassAttributeNode.create();
 
@@ -126,7 +126,7 @@ public class DynLoadFunctions {
     }
 
     @RBuiltin(name = "is.loaded", kind = INTERNAL, parameterNames = {"symbol", "PACKAGE", "type"}, behavior = READS_STATE)
-    public abstract static class IsLoaded extends RBuiltinNode {
+    public abstract static class IsLoaded extends RBuiltinNode.Arg3 {
         @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
 
         static {
@@ -162,7 +162,7 @@ public class DynLoadFunctions {
     }
 
     @RBuiltin(name = "getSymbolInfo", kind = INTERNAL, parameterNames = {"symbol", "package", "withRegistrationInfo"}, behavior = READS_STATE)
-    public abstract static class GetSymbolInfo extends RBuiltinNode {
+    public abstract static class GetSymbolInfo extends RBuiltinNode.Arg3 {
         @Child DLL.RFindSymbolNode findSymbolNode = DLL.RFindSymbolNode.create();
 
         static {
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 2cdec5a98cd8b5e42dffc9cff0b8dfe6c72a0ef1..edff830f7290665d07eb221b1e6d6af7d14e77b2 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "encodeString", kind = INTERNAL, parameterNames = {"x", "width", "quote", "justify", "na.encode"}, behavior = READS_STATE)
-public abstract class EncodeString extends RBuiltinNode {
+public abstract class EncodeString extends RBuiltinNode.Arg5 {
 
     private enum JUSTIFY {
         LEFT,
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 6bd38e8e75e37b29273ca31e9848253ecf4aaefd..e06312a5ede08cdc45e8732e122d35663ddd897d 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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public class EncodingFunctions {
 
     @RBuiltin(name = "Encoding", kind = INTERNAL, parameterNames = "x", behavior = PURE)
-    public abstract static class Encoding extends RBuiltinNode {
+    public abstract static class Encoding extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Encoding.class);
@@ -53,7 +53,7 @@ public class EncodingFunctions {
     }
 
     @RBuiltin(name = "setEncoding", kind = INTERNAL, parameterNames = {"x", "value"}, behavior = PURE)
-    public abstract static class SetEncoding extends RBuiltinNode {
+    public abstract static class SetEncoding extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(SetEncoding.class);
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 c3e0789b4346bccf34bd8440f737232333ead249..1f9ed8bb2281941355312a476d4316dcd3249e62 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
@@ -93,11 +93,8 @@ import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
  */
 public class EnvFunctions {
 
-    protected abstract static class Adapter extends RBuiltinNode {
-    }
-
     @RBuiltin(name = "as.environment", kind = PRIMITIVE, parameterNames = {"fun"}, dispatch = INTERNAL_GENERIC, behavior = COMPLEX)
-    public abstract static class AsEnvironment extends Adapter {
+    public abstract static class AsEnvironment extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(AsEnvironment.class);
@@ -200,7 +197,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "emptyenv", kind = PRIMITIVE, parameterNames = {}, behavior = PURE)
-    public abstract static class EmptyEnv extends RBuiltinNode {
+    public abstract static class EmptyEnv extends RBuiltinNode.Arg0 {
 
         @Specialization
         protected REnvironment emptyenv() {
@@ -209,7 +206,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "globalenv", kind = PRIMITIVE, parameterNames = {}, behavior = PURE)
-    public abstract static class GlobalEnv extends RBuiltinNode {
+    public abstract static class GlobalEnv extends RBuiltinNode.Arg0 {
 
         @Specialization
         protected Object globalenv() {
@@ -221,7 +218,7 @@ public class EnvFunctions {
      * Returns the "package:base" environment.
      */
     @RBuiltin(name = "baseenv", kind = PRIMITIVE, parameterNames = {}, behavior = PURE)
-    public abstract static class BaseEnv extends RBuiltinNode {
+    public abstract static class BaseEnv extends RBuiltinNode.Arg0 {
 
         @Specialization
         protected Object baseenv() {
@@ -230,7 +227,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "topenv", kind = INTERNAL, parameterNames = {"envir", "matchThisEnv"}, behavior = COMPLEX)
-    public abstract static class TopEnv extends Adapter {
+    public abstract static class TopEnv extends RBuiltinNode.Arg2 {
 
         static {
             Casts.noCasts(TopEnv.class);
@@ -238,6 +235,9 @@ public class EnvFunctions {
 
         @Child private FrameFunctions.ParentFrame parentFrameNode;
 
+        @Override
+        public abstract Object execute(VirtualFrame frame, Object execute, Object instance);
+
         @Specialization
         protected REnvironment topEnv(REnvironment env, REnvironment matchThisEnv) {
             return doTopEnv(matchThisEnv, env);
@@ -270,7 +270,7 @@ public class EnvFunctions {
         }
 
         @TruffleBoundary
-        private static REnvironment doTopEnv(REnvironment target, final REnvironment envArg) {
+        private static REnvironment doTopEnv(REnvironment target, REnvironment envArg) {
             REnvironment env = envArg;
             while (env != REnvironment.emptyEnv()) {
                 if (env == target || env == REnvironment.globalEnv() || env == REnvironment.baseEnv() || env == REnvironment.baseNamespaceEnv() || env.isPackageEnv() != null || env.isNamespaceEnv() ||
@@ -281,10 +281,11 @@ public class EnvFunctions {
             }
             return REnvironment.globalEnv();
         }
+
     }
 
     @RBuiltin(name = "parent.env", kind = INTERNAL, parameterNames = {"env"}, behavior = READS_FRAME)
-    public abstract static class ParentEnv extends Adapter {
+    public abstract static class ParentEnv extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(ParentEnv.class);
@@ -301,7 +302,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "parent.env<-", kind = INTERNAL, parameterNames = {"env", "value"}, behavior = COMPLEX)
-    public abstract static class SetParentEnv extends Adapter {
+    public abstract static class SetParentEnv extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(SetParentEnv.class);
@@ -321,7 +322,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "is.environment", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class IsEnvironment extends RBuiltinNode {
+    public abstract static class IsEnvironment extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(IsEnvironment.class);
@@ -334,7 +335,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "environment", kind = INTERNAL, parameterNames = {"fun"}, behavior = COMPLEX)
-    public abstract static class Environment extends RBuiltinNode {
+    public abstract static class Environment extends RBuiltinNode.Arg1 {
 
         private final ConditionProfile attributable = ConditionProfile.createBinaryProfile();
         @Child private GetFixedAttributeNode getEnvAttrNode;
@@ -404,7 +405,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "environment<-", kind = PRIMITIVE, parameterNames = {"env", "value"}, behavior = COMPLEX)
-    public abstract static class UpdateEnvironment extends RBuiltinNode {
+    public abstract static class UpdateEnvironment extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(UpdateEnvironment.class);
@@ -484,7 +485,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "environmentName", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
-    public abstract static class EnvironmentName extends RBuiltinNode {
+    public abstract static class EnvironmentName extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(EnvironmentName.class);
@@ -503,7 +504,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "new.env", kind = INTERNAL, parameterNames = {"hash", "parent", "size"}, behavior = COMPLEX)
-    public abstract static class NewEnv extends RBuiltinNode {
+    public abstract static class NewEnv extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(NewEnv.class);
@@ -522,7 +523,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "search", kind = INTERNAL, parameterNames = {}, behavior = COMPLEX)
-    public abstract static class Search extends RBuiltinNode {
+    public abstract static class Search extends RBuiltinNode.Arg0 {
         @Specialization
         protected RStringVector search() {
             return RDataFactory.createStringVector(REnvironment.searchPath(), RDataFactory.COMPLETE_VECTOR);
@@ -530,7 +531,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "lockEnvironment", visibility = OFF, kind = INTERNAL, parameterNames = {"env", "bindings"}, behavior = COMPLEX)
-    public abstract static class LockEnvironment extends RBuiltinNode {
+    public abstract static class LockEnvironment extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(LockEnvironment.class);
@@ -547,7 +548,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "environmentIsLocked", kind = INTERNAL, parameterNames = {"env"}, behavior = PURE)
-    public abstract static class EnvironmentIsLocked extends RBuiltinNode {
+    public abstract static class EnvironmentIsLocked extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(EnvironmentIsLocked.class);
@@ -561,7 +562,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "lockBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = COMPLEX)
-    public abstract static class LockBinding extends RBuiltinNode {
+    public abstract static class LockBinding extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(LockBinding.class);
@@ -577,7 +578,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "unlockBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = COMPLEX)
-    public abstract static class UnlockBinding extends RBuiltinNode {
+    public abstract static class UnlockBinding extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(UnlockBinding.class);
@@ -593,7 +594,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "bindingIsLocked", kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = PURE)
-    public abstract static class BindingIsLocked extends RBuiltinNode {
+    public abstract static class BindingIsLocked extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(BindingIsLocked.class);
@@ -608,7 +609,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "makeActiveBinding", visibility = OFF, kind = INTERNAL, parameterNames = {"sym", "fun", "env"}, behavior = COMPLEX)
-    public abstract static class MakeActiveBinding extends RBuiltinNode {
+    public abstract static class MakeActiveBinding extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(MakeActiveBinding.class);
@@ -653,7 +654,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "bindingIsActive", kind = INTERNAL, parameterNames = {"sym", "env"}, behavior = PURE)
-    public abstract static class BindingIsActive extends RBuiltinNode {
+    public abstract static class BindingIsActive extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(BindingIsActive.class);
@@ -672,7 +673,7 @@ public class EnvFunctions {
     }
 
     @RBuiltin(name = "env2list", kind = INTERNAL, parameterNames = {"x", "all.names", "sorted"}, behavior = PURE)
-    public abstract static class EnvToList extends RBuiltinNode {
+    public abstract static class EnvToList extends RBuiltinNode.Arg3 {
 
         @Child private CopyNode copy;
 
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 2164f840c03c283d9dd476ece6fc2f227b3c5136..1a2c94f5c7672ef8d4a1b803f0c92c4b65b3e287 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
@@ -62,7 +62,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * Contains the {@code eval} {@code .Internal} implementation.
  */
 @RBuiltin(name = "eval", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"expr", "envir", "enclos"}, behavior = COMPLEX)
-public abstract class Eval extends RBuiltinNode {
+public abstract class Eval extends RBuiltinNode.Arg3 {
 
     /**
      * Profiling for catching {@link ReturnException}s.
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 f08f18daa3dc3478474890ca9636265be26f71f3..2e8a04837d0705b28bb39734801bcd3b40776db6 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "exists", kind = INTERNAL, parameterNames = {"x", "envir", "mode", "inherits"}, behavior = PURE)
-public abstract class Exists extends RBuiltinNode {
+public abstract class Exists extends RBuiltinNode.Arg4 {
 
     @Child private TypeFromModeNode typeFromMode = TypeFromModeNodeGen.create();
 
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 f4b9d0c8e54fa4bd3fc9f9798019d4f8278b0496..6e245e1ed74d87338ed744ce95b59203b8df644d 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RPromise;
 
 @RBuiltin(name = "expression", kind = PRIMITIVE, parameterNames = {"..."}, nonEvalArgs = 0, behavior = PURE)
-public abstract class Expression extends RBuiltinNode {
+public abstract class Expression extends RBuiltinNode.Arg1 {
     /*
      * Owing to the nonEvalArgs, all arguments are RPromise, but an expression may contain
      * non-RLanguage elements.
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 ef3d5d4f019013022e896e43058bac6bd1cb7d45..14493a1eebca3358f8b7e2799b87395bdec1a03a 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
@@ -88,7 +88,7 @@ import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 public class FileFunctions {
 
     @RBuiltin(name = "file.access", kind = INTERNAL, parameterNames = {"names", "mode"}, behavior = IO)
-    public abstract static class FileAccess extends RBuiltinNode {
+    public abstract static class FileAccess extends RBuiltinNode.Arg2 {
         private static final int EXECUTE = 1;
         private static final int WRITE = 2;
         private static final int READ = 4;
@@ -124,7 +124,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "file.append", kind = INTERNAL, parameterNames = {"file1", "file2"}, behavior = IO)
-    public abstract static class FileAppend extends RBuiltinNode {
+    public abstract static class FileAppend extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(FileAppend.class);
@@ -220,7 +220,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "file.create", kind = INTERNAL, parameterNames = {"vec", "showWarnings"}, behavior = IO)
-    public abstract static class FileCreate extends RBuiltinNode {
+    public abstract static class FileCreate extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(FileCreate.class);
@@ -254,7 +254,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "file.info", kind = INTERNAL, parameterNames = {"fn", "extra_cols"}, behavior = IO)
-    public abstract static class FileInfo extends RBuiltinNode {
+    public abstract static class FileInfo extends RBuiltinNode.Arg2 {
         // @formatter:off
         private  enum Column {
             size, isdir, mode, mtime, ctime, atime, uid, gid, uname, grname;
@@ -424,7 +424,7 @@ public class FileFunctions {
         }
     }
 
-    private abstract static class FileLinkAdaptor extends RBuiltinNode {
+    private abstract static class FileLinkAdaptor extends RBuiltinNode.Arg2 {
 
         protected static void casts(Class<? extends FileLinkAdaptor> builtinClass) {
             Casts casts = new Casts(builtinClass);
@@ -502,7 +502,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "file.remove", kind = INTERNAL, parameterNames = {"file"}, behavior = IO)
-    public abstract static class FileRemove extends RBuiltinNode {
+    public abstract static class FileRemove extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(FileRemove.class);
@@ -531,7 +531,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "file.rename", kind = INTERNAL, parameterNames = {"from", "to"}, behavior = IO)
-    public abstract static class FileRename extends RBuiltinNode {
+    public abstract static class FileRename extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(FileRename.class);
@@ -567,7 +567,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "file.exists", kind = INTERNAL, parameterNames = {"file"}, behavior = IO)
-    public abstract static class FileExists extends RBuiltinNode {
+    public abstract static class FileExists extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(FileExists.class);
@@ -594,7 +594,7 @@ public class FileFunctions {
 
     // TODO Implement all the options
     @RBuiltin(name = "list.files", kind = INTERNAL, parameterNames = {"path", "pattern", "all.files", "full.names", "recursive", "ignore.case", "include.dirs", "no.."}, behavior = IO)
-    public abstract static class ListFiles extends RBuiltinNode {
+    public abstract static class ListFiles extends RBuiltinNode.Arg8 {
         private static final String DOT = ".";
         private static final String DOTDOT = "..";
 
@@ -738,7 +738,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "list.dirs", kind = INTERNAL, parameterNames = {"directory", "full.names", "recursive"}, behavior = IO)
-    public abstract static class ListDirs extends RBuiltinNode {
+    public abstract static class ListDirs extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(ListDirs.class);
@@ -794,7 +794,7 @@ public class FileFunctions {
 
     // TODO handle the general case, which is similar to paste
     @RBuiltin(name = "file.path", kind = INTERNAL, parameterNames = {"paths", "fsep"}, behavior = IO)
-    public abstract static class FilePath extends RBuiltinNode {
+    public abstract static class FilePath extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(FilePath.class);
@@ -893,7 +893,7 @@ public class FileFunctions {
      * {@code file.copy} builtin. This is only called when the target is a directory.
      */
     @RBuiltin(name = "file.copy", kind = INTERNAL, parameterNames = {"from", "to", "overwrite", "recursive", "copy.mode", "copy.date"}, behavior = IO)
-    public abstract static class FileCopy extends RBuiltinNode {
+    public abstract static class FileCopy extends RBuiltinNode.Arg6 {
 
         static {
             Casts casts = new Casts(FileCopy.class);
@@ -1028,7 +1028,7 @@ 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 {
+    public abstract static class FileShow extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(FileShow.class);
@@ -1086,7 +1086,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "dirname", kind = INTERNAL, parameterNames = {"path"}, behavior = IO)
-    public abstract static class DirName extends RBuiltinNode {
+    public abstract static class DirName extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(DirName.class);
@@ -1105,7 +1105,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "basename", kind = INTERNAL, parameterNames = {"path"}, behavior = IO)
-    public abstract static class BaseName extends RBuiltinNode {
+    public abstract static class BaseName extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(BaseName.class);
@@ -1124,7 +1124,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "unlink", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "recursive", "force"}, behavior = IO)
-    public abstract static class Unlink extends RBuiltinNode {
+    public abstract static class Unlink extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(Unlink.class);
@@ -1193,7 +1193,7 @@ 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 {
+    public abstract static class DirCreate extends RBuiltinNode.Arg4 {
 
         static {
             Casts casts = new Casts(DirCreate.class);
@@ -1251,7 +1251,7 @@ public class FileFunctions {
     }
 
     @RBuiltin(name = "dir.exists", kind = INTERNAL, parameterNames = "paths", behavior = IO)
-    public abstract static class DirExists extends RBuiltinNode {
+    public abstract static class DirExists extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(DirExists.class);
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 3368086a659ce6075b865ceb209bfabdbddb19b2..3cef036d53cbbb707ffd9819a0bcb2f02abd496c 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 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 {
+public abstract class ForceAndCall extends RBuiltinNode.Arg3 {
 
     @Child private RExplicitCallNode call = RExplicitCallNode.create();
 
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 ce083781b25870a75ff9adef33030549d86bac59..91e682f99967cba54c235fa4dc0aa4990d4befac 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
 @RBuiltin(name = "formals", kind = INTERNAL, parameterNames = {"fun"}, behavior = PURE)
-public abstract class Formals extends RBuiltinNode {
+public abstract class Formals extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(Formals.class);
@@ -72,9 +72,6 @@ public abstract class Formals extends RBuiltinNode {
             return RNull.instance;
         }
         FunctionDefinitionNode fdNode = (FunctionDefinitionNode) fun.getTarget().getRootNode();
-        if (fdNode.getParameterCount() == 0) {
-            return RNull.instance;
-        }
         FormalArguments formalArgs = fdNode.getFormalArguments();
         Object succ = RNull.instance;
         for (int i = formalArgs.getSignature().getLength() - 1; i >= 0; i--) {
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 d383f0330e1357194afabd1adf87c54d99fb1e55..aaeb3235e09b123a76e96682b4f156e878de2b83 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
@@ -44,7 +44,7 @@ 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)
-public abstract class Format extends RBuiltinNode {
+public abstract class Format extends RBuiltinNode.Arg9 {
 
     @Child private CastIntegerNode castInteger;
     @Child protected ValuePrinterNode valuePrinter = new ValuePrinterNode();
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 f0d0e4ea81556b68ea29946810c34c653d6c03b3..bab1c075934a48b4b486a6b16ec598ad46f3743f 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
@@ -29,7 +29,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "formatC", kind = INTERNAL, parameterNames = {"x", "mode", "width", "digits", "format", "flag", "i.strlen"}, behavior = PURE)
-public abstract class FormatC extends RBuiltinNode {
+public abstract class FormatC extends RBuiltinNode.Arg7 {
 
     @Child private RoundArithmetic round = new RoundArithmetic();
 
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 5902eeab4d5f65472b1a3fb9be257f286895a15b..45721e4ced626d59066cacbce3529fe5d056a3b2 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
@@ -79,6 +79,7 @@ import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.gnur.SEXPTYPE;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
@@ -91,7 +92,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  */
 public class FrameFunctions {
 
-    public abstract static class FrameHelper extends RBuiltinNode {
+    public static final class FrameHelper extends RBaseNode {
 
         private final ConditionProfile currentFrameProfile = ConditionProfile.createBinaryProfile();
 
@@ -100,7 +101,11 @@ public class FrameFunctions {
          * only use the frame internally should not materialize it, i.e., they should use
          * {@link FrameAccess#READ_ONLY} or {@link FrameAccess#READ_WRITE}.
          */
-        protected abstract FrameAccess frameAccess();
+        private final FrameAccess access;
+
+        public FrameHelper(FrameAccess access) {
+            this.access = access;
+        }
 
         protected Frame getFrame(VirtualFrame frame, int n) {
             int actualFrame = decodeFrameNumber(RArguments.getCall(frame), n);
@@ -162,7 +167,7 @@ public class FrameFunctions {
                     }
                     notifyRCallNodes(actualFrame, RArguments.getCall(frame));
                 }
-                return Utils.getStackFrame(frameAccess(), actualFrame);
+                return Utils.getStackFrame(access, actualFrame);
             }
         }
 
@@ -182,18 +187,15 @@ public class FrameFunctions {
     }
 
     @RBuiltin(name = "sys.call", kind = INTERNAL, parameterNames = {"which"}, behavior = COMPLEX)
-    public abstract static class SysCall extends FrameHelper {
+    public abstract static class SysCall extends RBuiltinNode.Arg1 {
+
+        @Child private FrameHelper helper = new FrameHelper(FrameAccess.READ_ONLY);
 
         static {
             Casts casts = new Casts(SysCall.class);
             casts.arg("which").asIntegerVector().findFirst();
         }
 
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.READ_ONLY;
-        }
-
         @Specialization
         protected Object sysCall(VirtualFrame frame, int which) {
             /*
@@ -204,7 +206,7 @@ public class FrameFunctions {
 
         @TruffleBoundary
         private Object createCall(RCaller currentCall, int which) {
-            RCaller call = getCall(currentCall, which);
+            RCaller call = helper.getCall(currentCall, which);
             assert !call.isPromise();
             if (call == null || !call.isValidCaller()) {
                 return RNull.instance;
@@ -228,12 +230,9 @@ public class FrameFunctions {
      * using "..." that make the code a lot more complex that it seems it ought to be.
      */
     @RBuiltin(name = "match.call", kind = INTERNAL, parameterNames = {"definition", "call", "expand.dots", "envir"}, behavior = COMPLEX)
-    public abstract static class MatchCall extends FrameHelper {
+    public abstract static class MatchCall extends RBuiltinNode.Arg4 {
 
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.READ_ONLY;
-        }
+        @Child private FrameHelper helper = new FrameHelper(FrameAccess.READ_ONLY);
 
         static {
             Casts casts = new Casts(MatchCall.class);
@@ -402,7 +401,7 @@ public class FrameFunctions {
     }
 
     @RBuiltin(name = "sys.nframe", kind = INTERNAL, parameterNames = {}, behavior = COMPLEX)
-    public abstract static class SysNFrame extends RBuiltinNode {
+    public abstract static class SysNFrame extends RBuiltinNode.Arg0 {
 
         private final BranchProfile isPromiseCurrentProfile = BranchProfile.create();
         private final BranchProfile isPromiseResultProfile = BranchProfile.create();
@@ -423,13 +422,11 @@ public class FrameFunctions {
         }
     }
 
-    private abstract static class DeoptHelper extends FrameHelper {
-        protected final PromiseDeoptimizeFrameNode deoptFrameNode = new PromiseDeoptimizeFrameNode();
-
-    }
-
     @RBuiltin(name = "sys.frame", kind = INTERNAL, parameterNames = {"which"}, behavior = COMPLEX)
-    public abstract static class SysFrame extends DeoptHelper {
+    public abstract static class SysFrame extends RBuiltinNode.Arg1 {
+
+        @Child private FrameHelper helper = new FrameHelper(FrameAccess.MATERIALIZE);
+        @Child private PromiseDeoptimizeFrameNode deoptFrameNode = new PromiseDeoptimizeFrameNode();
 
         private final ConditionProfile zeroProfile = ConditionProfile.createBinaryProfile();
 
@@ -439,11 +436,6 @@ public class FrameFunctions {
             return SysFrameNodeGen.create();
         }
 
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.MATERIALIZE;
-        }
-
         static {
             Casts casts = new Casts(SysFrame.class);
             casts.arg("which").asIntegerVector().findFirst();
@@ -455,23 +447,21 @@ public class FrameFunctions {
             if (zeroProfile.profile(which == 0)) {
                 result = REnvironment.globalEnv();
             } else {
-                Frame callerFrame = getFrame(frame, which);
+                Frame callerFrame = helper.getFrame(frame, which);
                 result = REnvironment.frameToEnvironment(callerFrame.materialize());
             }
 
             // Deoptimize every promise which is now in this frame, as it might leave it's stack
             deoptFrameNode.deoptimizeFrame(result.getFrame());
-
             return result;
         }
     }
 
     @RBuiltin(name = "sys.frames", kind = INTERNAL, parameterNames = {}, behavior = COMPLEX)
-    public abstract static class SysFrames extends DeoptHelper {
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.MATERIALIZE;
-        }
+    public abstract static class SysFrames extends RBuiltinNode.Arg0 {
+
+        @Child private FrameHelper helper = new FrameHelper(FrameAccess.MATERIALIZE);
+        @Child private PromiseDeoptimizeFrameNode deoptFrameNode = new PromiseDeoptimizeFrameNode();
 
         @Specialization
         protected Object sysFrames(VirtualFrame frame) {
@@ -482,7 +472,7 @@ public class FrameFunctions {
                 RPairList result = RDataFactory.createPairList();
                 RPairList next = result;
                 for (int i = 1; i < depth; i++) {
-                    MaterializedFrame mf = getNumberedFrame(frame, i).materialize();
+                    MaterializedFrame mf = helper.getNumberedFrame(frame, i).materialize();
                     deoptFrameNode.deoptimizeFrame(mf);
                     next.setCar(REnvironment.frameToEnvironment(mf));
                     if (i != depth - 1) {
@@ -499,12 +489,7 @@ public class FrameFunctions {
     }
 
     @RBuiltin(name = "sys.calls", kind = INTERNAL, parameterNames = {}, behavior = COMPLEX)
-    public abstract static class SysCalls extends FrameHelper {
-
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.READ_ONLY;
-        }
+    public abstract static class SysCalls extends RBuiltinNode.Arg0 {
 
         @Specialization
         protected Object sysCalls(VirtualFrame frame) {
@@ -546,7 +531,7 @@ public class FrameFunctions {
     }
 
     @RBuiltin(name = "sys.parent", kind = INTERNAL, parameterNames = {"n"}, behavior = COMPLEX)
-    public abstract static class SysParent extends RBuiltinNode {
+    public abstract static class SysParent extends RBuiltinNode.Arg1 {
 
         private final BranchProfile nullCallerProfile = BranchProfile.create();
         private final BranchProfile promiseProfile = BranchProfile.create();
@@ -577,14 +562,11 @@ public class FrameFunctions {
     }
 
     @RBuiltin(name = "sys.function", kind = INTERNAL, parameterNames = {"which"}, splitCaller = true, alwaysSplit = true, behavior = COMPLEX)
-    public abstract static class SysFunction extends FrameHelper {
+    public abstract static class SysFunction extends RBuiltinNode.Arg1 {
 
-        public abstract Object executeObject(VirtualFrame frame, int which);
+        @Child private FrameHelper helper = new FrameHelper(FrameAccess.READ_ONLY);
 
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.READ_ONLY;
-        }
+        public abstract Object executeObject(VirtualFrame frame, int which);
 
         static {
             Casts casts = new Casts(SysFunction.class);
@@ -594,7 +576,7 @@ public class FrameFunctions {
         @Specialization
         protected Object sysFunction(VirtualFrame frame, int which) {
             // N.B. Despite the spec, n==0 is treated as the current function
-            Frame callerFrame = getFrame(frame, which);
+            Frame callerFrame = helper.getFrame(frame, which);
             RFunction func = RArguments.getFunction(callerFrame);
 
             if (func == null) {
@@ -606,12 +588,7 @@ public class FrameFunctions {
     }
 
     @RBuiltin(name = "sys.parents", kind = INTERNAL, parameterNames = {}, behavior = COMPLEX)
-    public abstract static class SysParents extends FrameHelper {
-
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.READ_ONLY;
-        }
+    public abstract static class SysParents extends RBuiltinNode.Arg0 {
 
         @Specialization
         protected RIntVector sysParents(VirtualFrame frame) {
@@ -650,7 +627,9 @@ public class FrameFunctions {
      * The environment of the caller of the function that called parent.frame.
      */
     @RBuiltin(name = "parent.frame", kind = SUBSTITUTE, parameterNames = {"n"}, behavior = COMPLEX)
-    public abstract static class ParentFrame extends FrameHelper {
+    public abstract static class ParentFrame extends RBuiltinNode.Arg1 {
+
+        @Child private FrameHelper helper = new FrameHelper(FrameAccess.MATERIALIZE);
 
         private final BranchProfile nullCallerProfile = BranchProfile.create();
         private final BranchProfile promiseProfile = BranchProfile.create();
@@ -668,11 +647,6 @@ public class FrameFunctions {
             return new Object[]{1};
         }
 
-        @Override
-        protected final FrameAccess frameAccess() {
-            return FrameAccess.MATERIALIZE;
-        }
-
         @Specialization(guards = "n == 1")
         protected REnvironment parentFrameDirect(VirtualFrame frame, @SuppressWarnings("unused") int n,
                         @Cached("new()") GetCallerFrameNode getCaller) {
@@ -709,7 +683,7 @@ public class FrameFunctions {
             // */
             // parentDepth--;
             // }
-            return REnvironment.frameToEnvironment(getNumberedFrame(frame, call.getDepth()).materialize());
+            return REnvironment.frameToEnvironment(helper.getNumberedFrame(frame, call.getDepth()).materialize());
         }
     }
 }
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 ad8d21132c6fc067f75dc68ed45e317711fd6812..7a5326f06608a25a8f20b628016429db2a2d38aa 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
@@ -28,7 +28,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 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.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -37,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 
 @RBuiltin(name = "gc", kind = INTERNAL, parameterNames = {"verbose", "reset"}, behavior = COMPLEX)
-public abstract class Gc extends RBuiltinNode {
+public abstract class Gc extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(Gc.class);
@@ -48,15 +47,13 @@ public abstract class Gc extends RBuiltinNode {
     @SuppressWarnings("unused")
     @Specialization
     protected RDoubleVector gc(boolean verbose, boolean reset) {
-        doGc();
+        /*
+         * It is rarely advisable to actually force a gc in Java, therefore we simply ignore this
+         * builtin.
+         */
         // TODO: somehow produce the (semi?) correct values
         double[] data = new double[14];
         Arrays.fill(data, RRuntime.DOUBLE_NA);
         return RDataFactory.createDoubleVector(data, RDataFactory.INCOMPLETE_VECTOR);
     }
-
-    @TruffleBoundary
-    private static void doGc() {
-        System.gc();
-    }
 }
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 2a2ddedc86d4c3646e9a1e66ae271b6ab961dc78..62e9ca8f725537af09f60666ce0fd99ca7b3ddcf 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
@@ -21,7 +21,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "class", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-public abstract class GetClass extends RBuiltinNode {
+public abstract class GetClass extends RBuiltinNode.Arg1 {
 
     @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(true, false);
 
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 42030e3dde9ea0decdd1defebb674c50434ba004..a05fba7d0a78b52737beb2200532f51fb97e55e3 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
@@ -41,7 +41,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.api.profiles.ConditionProfile;
-import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
@@ -73,14 +72,16 @@ import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * assert: not expected to be fast even when called as, e.g., {@code get("x")}.
  */
 public class GetFunctions {
-    public abstract static class Adapter extends RBuiltinNode {
-        protected final ValueProfile modeProfile = ValueProfile.createIdentityProfile();
+    private static final class Helper extends RBaseNode {
+
         protected final BranchProfile recursiveProfile = BranchProfile.create();
+
         @Child private PromiseHelperNode promiseHelper = new PromiseHelperNode();
         @Child protected TypeFromModeNode typeFromMode = TypeFromModeNodeGen.create();
 
@@ -160,11 +161,13 @@ public class GetFunctions {
     }
 
     @RBuiltin(name = "get", kind = INTERNAL, parameterNames = {"x", "envir", "mode", "inherits"}, behavior = COMPLEX)
-    public abstract static class Get extends Adapter {
+    public abstract static class Get extends RBuiltinNode.Arg4 {
+
+        @Child private Helper helper = new Helper();
 
         private final ConditionProfile inheritsProfile = ConditionProfile.createBinaryProfile();
 
-        public abstract Object execute(VirtualFrame frame, String x, REnvironment environment, String mode, boolean inherits);
+        public abstract Object execute(VirtualFrame frame, Object what, Object where, String name, boolean inherits);
 
         static {
             Casts casts = new Casts(Get.class);
@@ -177,11 +180,11 @@ public class GetFunctions {
 
         @Specialization
         public Object get(VirtualFrame frame, String x, REnvironment envir, String mode, boolean inherits) {
-            RType modeType = typeFromMode.execute(mode);
+            RType modeType = helper.typeFromMode.execute(mode);
             if (inheritsProfile.profile(inherits)) {
-                return getInherits(frame, x, envir, modeType, mode, true);
+                return helper.getInherits(frame, x, envir, modeType, mode, true);
             } else {
-                return getAndCheck(frame, x, envir, modeType, mode, true);
+                return helper.getAndCheck(frame, x, envir, modeType, mode, true);
             }
         }
 
@@ -196,10 +199,13 @@ public class GetFunctions {
         protected Object get(VirtualFrame frame, String x, int envir, String mode, boolean inherits) {
             throw RInternalError.unimplemented();
         }
+
     }
 
     @RBuiltin(name = "get0", kind = INTERNAL, parameterNames = {"x", "envir", "mode", "inherits", "ifnotfound"}, behavior = COMPLEX)
-    public abstract static class Get0 extends Adapter {
+    public abstract static class Get0 extends RBuiltinNode.Arg5 {
+
+        @Child private Helper helper = new Helper();
 
         private final ConditionProfile inheritsProfile = ConditionProfile.createBinaryProfile();
 
@@ -215,11 +221,11 @@ public class GetFunctions {
         @Specialization
         protected Object get0(VirtualFrame frame, String x, REnvironment envir, String mode, boolean inherits, Object ifnotfound) {
             Object result;
-            RType modeType = typeFromMode.execute(mode);
+            RType modeType = helper.typeFromMode.execute(mode);
             if (inheritsProfile.profile(inherits)) {
-                result = getInherits(frame, x, envir, modeType, mode, false);
+                result = helper.getInherits(frame, x, envir, modeType, mode, false);
             } else {
-                result = getAndCheck(frame, x, envir, modeType, mode, false);
+                result = helper.getAndCheck(frame, x, envir, modeType, mode, false);
             }
             if (result == null) {
                 result = ifnotfound;
@@ -241,7 +247,9 @@ public class GetFunctions {
     }
 
     @RBuiltin(name = "mget", kind = INTERNAL, parameterNames = {"x", "envir", "mode", "ifnotfound", "inherits"}, behavior = COMPLEX)
-    public abstract static class MGet extends Adapter {
+    public abstract static class MGet extends RBuiltinNode.Arg5 {
+
+        @Child private Helper helper = new Helper();
 
         private final BranchProfile wrongLengthErrorProfile = BranchProfile.create();
 
@@ -317,12 +325,12 @@ public class GetFunctions {
                 if (inheritsProfile.profile(inherits)) {
                     Object r = envir.get(x);
                     if (r == null || !RRuntime.checkType(r, modeType)) {
-                        recursiveProfile.enter();
+                        helper.recursiveProfile.enter();
                         REnvironment env = envir;
                         while (env != REnvironment.emptyEnv()) {
                             env = env.getParent();
                             if (env != REnvironment.emptyEnv()) {
-                                r = checkPromise(frame, env.get(x), x);
+                                r = helper.checkPromise(frame, env.get(x), x);
                                 if (r != null && RRuntime.checkType(r, modeType)) {
                                     break;
                                 }
@@ -335,7 +343,7 @@ public class GetFunctions {
                         state.data[i] = r;
                     }
                 } else {
-                    Object r = checkPromise(frame, envir.get(x), x);
+                    Object r = helper.checkPromise(frame, envir.get(x), x);
                     if (r != null && RRuntime.checkType(r, modeType)) {
                         state.data[i] = r;
                     } else {
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 44d7c6121be8b7464d2335db425a38f9292ac0df..8301704079762b789c5b79c3d1395fd6e5680ea8 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 
 @RBuiltin(name = "oldClass", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-public abstract class GetOldClass extends RBuiltinNode {
+public abstract class GetOldClass extends RBuiltinNode.Arg1 {
 
     private final ConditionProfile isObjectProfile = ConditionProfile.createBinaryProfile();
     @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create();
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 4262e5e87af3166bce1bf154909a4098da57c73f..6368703c0f9698b69587643ea00236e65d394b5c 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
@@ -33,7 +33,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 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 {
+public abstract class GetText extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(GetText.class);
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 1e5ab0b3745b9f0e3134bd0d4c8857ab05fc4cc7..c8244e9b43e119641fcfe61092aaede81f6c5d26 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
@@ -33,7 +33,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 
 @RBuiltin(name = "getwd", kind = INTERNAL, parameterNames = {}, behavior = IO)
-public abstract class Getwd extends RBuiltinNode {
+public abstract class Getwd extends RBuiltinNode.Arg0 {
 
     @Child private BaseRFFI.GetwdNode getwdNode = BaseRFFI.GetwdNode.create();
 
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 f5ee34bcfe01ec3685f6507fa30db422ce37c81e..250ccd5ed618172464be2978a062bc7b18e4a4f8 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
@@ -29,9 +29,14 @@ import java.util.regex.PatternSyntaxException;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.NodeCost;
+import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+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;
@@ -48,6 +53,7 @@ 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.PCRERFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 /**
@@ -66,57 +72,58 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  * Parts of this code, notably the perl support, were translated from GnuR grep.c.
  */
 public class GrepFunctions {
-    public abstract static class CommonCodeAdapter extends RBuiltinNode {
-        @Child protected PCRERFFI.MaketablesNode maketablesNode = RFFIFactory.getRFFI().getPCRERFFI().createMaketablesNode();
-        @Child protected PCRERFFI.CompileNode compileNode = RFFIFactory.getRFFI().getPCRERFFI().createCompileNode();
+    protected static void castPattern(Casts casts) {
+        // with default error message, NO_CALLER does not work
+        casts.arg("pattern").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "pattern").asVector().mustBe(notEmpty(), RError.Message.INVALID_ARGUMENT,
+                        "pattern");
+    }
 
-        protected static void castPattern(Casts casts) {
-            // with default error message, NO_CALLER does not work
-            casts.arg("pattern").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "pattern").asVector().mustBe(notEmpty(), RError.Message.INVALID_ARGUMENT,
-                            "pattern");
-        }
+    protected static void castPatternSingle(Casts casts) {
+        // with default error message, NO_CALLER does not work
+        casts.arg("pattern").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "pattern").asVector().mustBe(notEmpty(), RError.Message.INVALID_ARGUMENT,
+                        "pattern").shouldBe(singleElement(), RError.Message.ARGUMENT_ONLY_FIRST, "pattern").findFirst();
+    }
 
-        protected static void castPatternSingle(Casts casts) {
-            // with default error message, NO_CALLER does not work
-            casts.arg("pattern").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "pattern").asVector().mustBe(notEmpty(), RError.Message.INVALID_ARGUMENT,
-                            "pattern").shouldBe(singleElement(), RError.Message.ARGUMENT_ONLY_FIRST, "pattern").findFirst();
-        }
+    protected static void castText(Casts casts, String textId) {
+        casts.arg(textId).mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, textId);
+    }
 
-        protected static void castText(Casts casts, String textId) {
-            casts.arg(textId).mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, textId);
-        }
+    protected static void castIgnoreCase(Casts casts) {
+        casts.arg("ignore.case").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+    }
 
-        protected static void castIgnoreCase(Casts casts) {
-            casts.arg("ignore.case").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
-        }
+    protected static void castPerl(Casts casts) {
+        casts.arg("perl").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+    }
 
-        protected static void castPerl(Casts casts) {
-            casts.arg("perl").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
-        }
+    protected static void castFixed(Casts casts, byte defaultValue) {
+        casts.arg("fixed").asLogicalVector().findFirst(defaultValue).map(toBoolean());
+    }
 
-        protected static void castFixed(Casts casts, byte defaultValue) {
-            casts.arg("fixed").asLogicalVector().findFirst(defaultValue).map(toBoolean());
-        }
+    protected static void castValue(Casts casts) {
+        casts.arg("value").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+    }
 
-        protected static void castValue(Casts casts) {
-            casts.arg("value").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
-        }
+    protected static void castCosts(Casts casts) {
+        casts.arg("costs").defaultError(RError.Message.INVALID_ARG, "costs").mustBe((missingValue().or(nullValue()).not())).asIntegerVector();
+    }
 
-        protected static void castUseBytes(Casts casts) {
-            casts.arg("useBytes").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
-        }
+    protected static void castUseBytes(Casts casts) {
+        casts.arg("useBytes").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+    }
 
-        protected static void castInvert(Casts casts) {
-            casts.arg("invert").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
-        }
+    protected static void castInvert(Casts casts) {
+        casts.arg("invert").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+    }
 
-        protected static void castCosts(Casts casts) {
-            casts.arg("costs").defaultError(RError.Message.INVALID_ARG, "costs").mustBe((missingValue().or(nullValue()).not())).asIntegerVector();
-        }
+    protected static void castBounds(Casts casts) {
+        casts.arg("bounds").defaultError(RError.Message.INVALID_ARG, "bounds").mustBe((missingValue().or(nullValue()).not())).asDoubleVector();
+    }
 
-        protected static void castBounds(Casts casts) {
-            casts.arg("bounds").defaultError(RError.Message.INVALID_ARG, "bounds").mustBe((missingValue().or(nullValue()).not())).asDoubleVector();
-        }
+    @NodeInfo(cost = NodeCost.NONE)
+    public static class CommonCodeNode extends RBaseNode {
+        @Child protected PCRERFFI.MaketablesNode maketablesNode = RFFIFactory.getRFFI().getPCRERFFI().createMaketablesNode();
+        @Child protected PCRERFFI.CompileNode compileNode = RFFIFactory.getRFFI().getPCRERFFI().createCompileNode();
 
         /**
          * Temporary method that handles the check for the arguments that are common to the majority
@@ -209,7 +216,7 @@ public class GrepFunctions {
         }
     }
 
-    private abstract static class GrepAdapter extends CommonCodeAdapter {
+    protected static final class GrepCommonCodeNode extends CommonCodeNode {
         @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
 
         protected Object doGrep(String patternArg, RAbstractStringVector vector, boolean ignoreCase, boolean value, boolean perlPar, boolean fixed,
@@ -292,7 +299,7 @@ public class GrepFunctions {
             }
         }
 
-        protected void findAllMatches(boolean[] result, String pattern, RAbstractStringVector vector, boolean fixed, boolean ignoreCase) {
+        protected static void findAllMatches(boolean[] result, String pattern, RAbstractStringVector vector, boolean fixed, boolean ignoreCase) {
             for (int i = 0; i < result.length; i++) {
                 String text = vector.getDataAt(i);
                 if (!RRuntime.isNA(text)) {
@@ -311,8 +318,21 @@ public class GrepFunctions {
         }
     }
 
+    public static CommonCodeNode createCommon() {
+        return new CommonCodeNode();
+    }
+
+    public static GrepCommonCodeNode createGrepCommon() {
+        return new GrepCommonCodeNode();
+    }
+
+    public static SubCommonCodeNode createSubCommon() {
+        return new SubCommonCodeNode();
+    }
+
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "grep", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "value", "perl", "fixed", "useBytes", "invert"}, behavior = PURE)
-    public abstract static class Grep extends GrepAdapter {
+    public abstract static class Grep extends RBuiltinNode.Arg8 {
 
         static {
             Casts casts = new Casts(Grep.class);
@@ -358,13 +378,15 @@ public class GrepFunctions {
         @Specialization
         @TruffleBoundary
         protected Object grepValueFalse(String patternArgVec, RAbstractStringVector vector, boolean ignoreCaseLogical, boolean valueLogical, boolean perlLogical, boolean fixedLogical,
-                        boolean useBytes, boolean invertLogical) {
-            return doGrep(patternArgVec, vector, ignoreCaseLogical, valueLogical, perlLogical, fixedLogical, useBytes, invertLogical, false);
+                        boolean useBytes, boolean invertLogical,
+                        @Cached("createGrepCommon()") GrepCommonCodeNode common) {
+            return common.doGrep(patternArgVec, vector, ignoreCaseLogical, valueLogical, perlLogical, fixedLogical, useBytes, invertLogical, false);
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "grepl", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "value", "perl", "fixed", "useBytes", "invert"}, behavior = PURE)
-    public abstract static class GrepL extends GrepAdapter {
+    public abstract static class GrepL extends RBuiltinNode.Arg8 {
 
         static {
             Casts casts = new Casts(GrepL.class);
@@ -380,21 +402,22 @@ public class GrepFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected Object grepl(String pattern, RAbstractStringVector vector, boolean ignoreCaseLogical, boolean valueLogical, boolean perlLogical, boolean fixedLogical,
-                        boolean useBytes, boolean invertLogical) {
+        protected Object grepl(String pattern, RAbstractStringVector vector, boolean ignoreCaseLogical, boolean valueLogical, boolean perlLogical, boolean fixedLogical, boolean useBytes,
+                        boolean invertLogical,
+                        @Cached("createGrepCommon()") GrepCommonCodeNode common) {
             // invert is passed but is always FALSE
-            return doGrep(pattern, vector, ignoreCaseLogical, valueLogical, perlLogical, fixedLogical, useBytes, invertLogical, true);
+            return common.doGrep(pattern, vector, ignoreCaseLogical, valueLogical, perlLogical, fixedLogical, useBytes, invertLogical, true);
         }
     }
 
-    protected abstract static class SubAdapter extends CommonCodeAdapter {
-        @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
+    protected static void castReplacement(Casts casts) {
+        // with default error message, NO_CALLER does not work
+        casts.arg("replacement").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "replacement").asVector().mustBe(notEmpty(), RError.Message.INVALID_ARGUMENT, "replacement").shouldBe(
+                        singleElement(), RError.Message.ARGUMENT_ONLY_FIRST, "replacement").findFirst();
+    }
 
-        protected static void castReplacement(Casts casts) {
-            // with default error message, NO_CALLER does not work
-            casts.arg("replacement").mustBe(stringValue(), RError.Message.INVALID_ARGUMENT, "replacement").asVector().mustBe(notEmpty(), RError.Message.INVALID_ARGUMENT, "replacement").shouldBe(
-                            singleElement(), RError.Message.ARGUMENT_ONLY_FIRST, "replacement").findFirst();
-        }
+    protected static final class SubCommonCodeNode extends CommonCodeNode {
+        @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
 
         protected RStringVector doSub(String patternArg, String replacementArg, RAbstractStringVector vector, boolean ignoreCase, boolean perlPar,
                         boolean fixedPar, @SuppressWarnings("unused") boolean useBytes, boolean gsub) {
@@ -662,8 +685,9 @@ public class GrepFunctions {
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "sub", kind = INTERNAL, parameterNames = {"pattern", "replacement", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
-    public abstract static class Sub extends SubAdapter {
+    public abstract static class Sub extends RBuiltinNode.Arg7 {
 
         static {
             Casts casts = new Casts(Sub.class);
@@ -678,14 +702,15 @@ public class GrepFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected RStringVector subRegexp(String patternArgVec, String replacementVec, RAbstractStringVector x, boolean ignoreCaseLogical, boolean perlLogical,
-                        boolean fixedLogical, boolean useBytes) {
-            return doSub(patternArgVec, replacementVec, x, ignoreCaseLogical, perlLogical, fixedLogical, useBytes, false);
+        protected RStringVector subRegexp(String patternArgVec, String replacementVec, RAbstractStringVector x, boolean ignoreCaseLogical, boolean perlLogical, boolean fixedLogical, boolean useBytes,
+                        @Cached("createSubCommon()") SubCommonCodeNode common) {
+            return common.doSub(patternArgVec, replacementVec, x, ignoreCaseLogical, perlLogical, fixedLogical, useBytes, false);
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "gsub", kind = INTERNAL, parameterNames = {"pattern", "replacement", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
-    public abstract static class GSub extends SubAdapter {
+    public abstract static class GSub extends RBuiltinNode.Arg7 {
 
         static {
             Casts casts = new Casts(GSub.class);
@@ -700,14 +725,15 @@ public class GrepFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected RStringVector gsub(String patternArgVec, String replacementVec, RAbstractStringVector x, boolean ignoreCaseLogical, boolean perlLogical,
-                        boolean fixedLogical, boolean useBytes) {
-            return doSub(patternArgVec, replacementVec, x, ignoreCaseLogical, perlLogical, fixedLogical, useBytes, true);
+        protected RStringVector gsub(String patternArgVec, String replacementVec, RAbstractStringVector x, boolean ignoreCaseLogical, boolean perlLogical, boolean fixedLogical, boolean useBytes,
+                        @Cached("createSubCommon()") SubCommonCodeNode common) {
+            return common.doSub(patternArgVec, replacementVec, x, ignoreCaseLogical, perlLogical, fixedLogical, useBytes, true);
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "regexpr", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
-    public abstract static class Regexp extends CommonCodeAdapter {
+    public abstract static class Regexp extends RBuiltinNode.Arg6 {
 
         @Child SetFixedAttributeNode setMatchLengthAttrNode = SetFixedAttributeNode.create("match.length");
         @Child SetFixedAttributeNode setUseBytesAttrNode = SetFixedAttributeNode.create("useBytes");
@@ -756,8 +782,9 @@ public class GrepFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCaseL, boolean perlL, boolean fixedL, boolean useBytesL) {
-            checkExtraArgs(false, false, false, useBytesL, false);
+        protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCaseL, boolean perlL, boolean fixedL, boolean useBytesL,
+                        @Cached("createCommon()") CommonCodeNode common) {
+            common.checkExtraArgs(false, false, false, useBytesL, false);
             boolean ignoreCase = ignoreCaseL;
             boolean fixed = fixedL;
             boolean perl = perlL;
@@ -782,7 +809,7 @@ public class GrepFunctions {
                 Arrays.fill(result, 1);
             } else {
                 for (int i = 0; i < vector.getLength(); i++) {
-                    Info res = getInfo(pattern, vector.getDataAt(i), ignoreCase, perl, fixed).get(0);
+                    Info res = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed).get(0);
                     result[i] = res.index;
                     matchLength[i] = res.size;
                     if (res.hasCapture) {
@@ -827,7 +854,7 @@ public class GrepFunctions {
             return ret;
         }
 
-        protected List<Info> getInfo(String pattern, String text, boolean ignoreCase, boolean perl, boolean fixed) {
+        protected List<Info> getInfo(CommonCodeNode common, String pattern, String text, boolean ignoreCase, boolean perl, boolean fixed) {
             List<Info> list = new ArrayList<>();
             if (fixed) {
                 int index = 0;
@@ -844,7 +871,7 @@ public class GrepFunctions {
                     index += pattern.length();
                 }
             } else if (perl) {
-                PCRERFFI.Result pcre = compilePerlPattern(pattern, ignoreCase);
+                PCRERFFI.Result pcre = common.compilePerlPattern(pattern, ignoreCase);
                 int maxCaptureCount = getCaptureCountNode.execute(pcre.result, 0);
                 int[] ovector = new int[(maxCaptureCount + 1) * 3];
                 int offset = 0;
@@ -897,6 +924,7 @@ public class GrepFunctions {
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "gregexpr", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class Gregexpr extends Regexp {
 
@@ -935,8 +963,9 @@ public class GrepFunctions {
         @Specialization
         @TruffleBoundary
         @Override
-        protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCaseL, boolean perlL, boolean fixedL, boolean useBytesL) {
-            checkExtraArgs(false, false, false, useBytesL, false);
+        protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCaseL, boolean perlL, boolean fixedL, boolean useBytesL,
+                        @Cached("createCommon()") CommonCodeNode common) {
+            common.checkExtraArgs(false, false, false, useBytesL, false);
             boolean ignoreCase = ignoreCaseL;
             boolean fixed = fixedL;
             boolean perl = perlL;
@@ -966,7 +995,7 @@ public class GrepFunctions {
                         setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
                     }
                 } else {
-                    List<Info> l = getInfo(pattern, vector.getDataAt(i), ignoreCase, perl, fixed);
+                    List<Info> l = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed);
                     res = toIndexOrSizeVector(l, true);
                     setMatchLengthAttrNode.execute(res, toIndexOrSizeVector(l, false));
                     if (useBytes) {
@@ -1043,8 +1072,9 @@ public class GrepFunctions {
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "agrep", kind = INTERNAL, parameterNames = {"pattern", "x", "ignore.case", "value", "costs", "bounds", "useBytes", "fixed"}, behavior = PURE)
-    public abstract static class AGrep extends CommonCodeAdapter {
+    public abstract static class AGrep extends RBuiltinNode.Arg8 {
 
         static {
             Casts casts = new Casts(AGrep.class);
@@ -1061,13 +1091,12 @@ public class GrepFunctions {
         @SuppressWarnings("unused")
         @Specialization
         @TruffleBoundary
-        protected Object aGrep(String pattern, RAbstractStringVector vector, boolean ignoreCase, boolean value, RAbstractIntVector costs, RAbstractDoubleVector bounds,
-                        boolean useBytes,
-                        boolean fixed) {
+        protected Object aGrep(String pattern, RAbstractStringVector vector, boolean ignoreCase, boolean value, RAbstractIntVector costs, RAbstractDoubleVector bounds, boolean useBytes, boolean fixed,
+                        @Cached("createCommon()") CommonCodeNode common) {
             // TODO implement completely; this is a very basic implementation for fixed=TRUE only.
-            checkExtraArgs(ignoreCase, false, false, useBytes, false);
-            valueCheck(value);
-            checkNotImplemented(!fixed, "fixed", false);
+            common.checkExtraArgs(ignoreCase, false, false, useBytes, false);
+            common.valueCheck(value);
+            common.checkNotImplemented(!fixed, "fixed", false);
             int[] tmp = new int[vector.getLength()];
             int numMatches = 0;
             long maxDistance = Math.round(pattern.length() * bounds.getDataAt(0));
@@ -1078,7 +1107,7 @@ public class GrepFunctions {
                     numMatches++;
                 }
             }
-            tmp = trimIntResult(tmp, numMatches, tmp.length);
+            tmp = common.trimIntResult(tmp, numMatches, tmp.length);
             if (tmp == null) {
                 return RDataFactory.createEmptyIntVector();
             } else {
@@ -1159,8 +1188,9 @@ public class GrepFunctions {
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "agrepl", kind = INTERNAL, parameterNames = {"pattern", "x", "ignore.case", "value", "costs", "bounds", "useBytes", "fixed"}, behavior = PURE)
-    public abstract static class AGrepL extends CommonCodeAdapter {
+    public abstract static class AGrepL extends RBuiltinNode.Arg8 {
 
         static {
             Casts casts = new Casts(AGrepL.class);
@@ -1177,11 +1207,10 @@ public class GrepFunctions {
         @SuppressWarnings("unused")
         @Specialization
         @TruffleBoundary
-        protected Object aGrep(String pattern, RAbstractStringVector vector, boolean ignoreCase, boolean value, RAbstractIntVector costs, RAbstractDoubleVector bounds,
-                        boolean useBytes,
-                        boolean fixed) {
+        protected Object aGrep(String pattern, RAbstractStringVector vector, boolean ignoreCase, boolean value, RAbstractIntVector costs, RAbstractDoubleVector bounds, boolean useBytes, boolean fixed,
+                        @Cached("createCommon()") CommonCodeNode common) {
             // TODO implement properly, this only supports strict equality!
-            checkExtraArgs(ignoreCase, false, false, useBytes, false);
+            common.checkExtraArgs(ignoreCase, false, false, useBytes, false);
             byte[] data = new byte[vector.getLength()];
             for (int i = 0; i < vector.getLength(); i++) {
                 data[i] = RRuntime.asLogical(pattern.equals(vector.getDataAt(i)));
@@ -1190,8 +1219,9 @@ public class GrepFunctions {
         }
     }
 
+    @ImportStatic(GrepFunctions.class)
     @RBuiltin(name = "strsplit", kind = INTERNAL, parameterNames = {"x", "split", "fixed", "perl", "useBytes"}, behavior = PURE)
-    public abstract static class Strsplit extends CommonCodeAdapter {
+    public abstract static class Strsplit extends RBuiltinNode.Arg5 {
         @Child PCRERFFI.ExecNode execNode = RFFIFactory.getRFFI().getPCRERFFI().createExecNode();
 
         static {
@@ -1207,14 +1237,14 @@ public class GrepFunctions {
 
         @Specialization
         @TruffleBoundary
-        protected RList split(RAbstractStringVector x, RAbstractStringVector splitArg, boolean fixedLogical, boolean perlLogical, @SuppressWarnings("unused") boolean useBytes) {
-            boolean fixed = fixedLogical;
-            boolean perl = checkPerlFixed(perlLogical, fixed);
+        protected RList split(RAbstractStringVector x, RAbstractStringVector splitArg, boolean fixed, boolean perlLogical, @SuppressWarnings("unused") boolean useBytes,
+                        @Cached("createCommon()") CommonCodeNode common) {
+            boolean perl = common.checkPerlFixed(perlLogical, fixed);
             RStringVector[] result = new RStringVector[x.getLength()];
             // treat split = NULL as split = ""
             RAbstractStringVector split = splitArg.getLength() == 0 ? RDataFactory.createStringVectorFromScalar("") : splitArg;
             String[] splits = new String[split.getLength()];
-            long pcreTables = perl ? maketablesNode.execute() : 0;
+            long pcreTables = perl ? common.maketablesNode.execute() : 0;
             PCRERFFI.Result[] pcreSplits = perl ? new PCRERFFI.Result[splits.length] : null;
 
             na.enable(x);
@@ -1223,7 +1253,7 @@ public class GrepFunctions {
                 splits[i] = fixed || perl ? split.getDataAt(i) : RegExp.checkPreDefinedClasses(split.getDataAt(i));
                 if (perl) {
                     if (!currentSplit.isEmpty()) {
-                        pcreSplits[i] = compileNode.execute(currentSplit, 0, pcreTables);
+                        pcreSplits[i] = common.compileNode.execute(currentSplit, 0, pcreTables);
                         if (pcreSplits[i].result == 0) {
                             // TODO output warning if pcre.errorMessage not NULL
                             throw error(RError.Message.INVALID_REGEXP, currentSplit);
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 f95d1d95a6cc753a4429f6da1d80e2c42131e028..965159a003e27909512544a134e49257fdb42e48 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
@@ -79,7 +79,7 @@ public class HiddenInternalFunctions {
      * Transcribed from GnuR {@code do_makeLazy} in src/main/builtin.c.
      */
     @RBuiltin(name = "makeLazy", visibility = OFF, kind = INTERNAL, parameterNames = {"names", "values", "expr", "eval.env", "assign.env"}, behavior = COMPLEX)
-    public abstract static class MakeLazy extends RBuiltinNode {
+    public abstract static class MakeLazy extends RBuiltinNode.Arg5 {
         @Child private Eval eval;
 
         private void initEval() {
@@ -142,7 +142,7 @@ public class HiddenInternalFunctions {
      * possibly with different names. Promises are not forced and active bindings are preserved.
      */
     @RBuiltin(name = "importIntoEnv", kind = INTERNAL, parameterNames = {"impenv", "impnames", "expenv", "expnames"}, behavior = COMPLEX)
-    public abstract static class ImportIntoEnv extends RBuiltinNode {
+    public abstract static class ImportIntoEnv extends RBuiltinNode.Arg4 {
 
         static {
             Casts casts = new Casts(ImportIntoEnv.class);
@@ -184,7 +184,7 @@ public class HiddenInternalFunctions {
      * Transcribed from {@code lazyLoaadDBFetch} in src/serialize.c.
      */
     @RBuiltin(name = "lazyLoadDBfetch", kind = PRIMITIVE, parameterNames = {"key", "datafile", "compressed", "envhook"}, behavior = PURE)
-    public abstract static class LazyLoadDBFetch extends RBuiltinNode {
+    public abstract static class LazyLoadDBFetch extends RBuiltinNode.Arg4 {
 
         @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2);
 
@@ -274,7 +274,7 @@ public class HiddenInternalFunctions {
     }
 
     @RBuiltin(name = "getRegisteredRoutines", kind = INTERNAL, parameterNames = "info", behavior = COMPLEX)
-    public abstract static class GetRegisteredRoutines extends RBuiltinNode {
+    public abstract static class GetRegisteredRoutines extends RBuiltinNode.Arg1 {
         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");
 
@@ -324,7 +324,7 @@ public class HiddenInternalFunctions {
     }
 
     @RBuiltin(name = "getVarsFromFrame", kind = INTERNAL, parameterNames = {"vars", "e", "force"}, behavior = COMPLEX)
-    public abstract static class GetVarsFromFrame extends RBuiltinNode {
+    public abstract static class GetVarsFromFrame extends RBuiltinNode.Arg3 {
         @Child private PromiseHelperNode promiseHelper;
 
         static {
@@ -361,7 +361,7 @@ public class HiddenInternalFunctions {
     }
 
     @RBuiltin(name = "lazyLoadDBinsertValue", kind = INTERNAL, parameterNames = {"value", "file", "ascii", "compsxp", "hook"}, behavior = COMPLEX)
-    public abstract static class LazyLoadDBinsertValue extends RBuiltinNode {
+    public abstract static class LazyLoadDBinsertValue extends RBuiltinNode.Arg5 {
 
         @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2);
 
@@ -465,7 +465,7 @@ public class HiddenInternalFunctions {
     }
 
     @RBuiltin(name = "lazyLoadDBflush", kind = INTERNAL, parameterNames = "path", behavior = COMPLEX)
-    public abstract static class LazyLoadDBFlush extends RBuiltinNode {
+    public abstract static class LazyLoadDBFlush extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(LazyLoadDBFlush.class);
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 c03a1d9ba813e7286c03a23161d055676baf2c5c..4b75dccff92fd1ddda1fb5943fb4c8361eb1ad68 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 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 {
+public abstract class IConv extends RBuiltinNode.Arg6 {
 
     static {
         Casts casts = new Casts(IConv.class);
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 bf863d14acfd0c6d136e9e033d32eb907d7957a3..9200d000ff439387eddd20b366953f7acfae0a2c 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
@@ -65,7 +65,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  * checked for NA (regardless of whether they are used).
  */
 @RBuiltin(name = "identical", kind = INTERNAL, parameterNames = {"x", "y", "num.eq", "single.NA", "attrib.as.set", "ignore.bytecode", "ignore.environment"}, behavior = PURE)
-public abstract class Identical extends RBuiltinNode {
+public abstract class Identical extends RBuiltinNode.Arg7 {
 
     protected abstract byte executeByte(Object x, Object y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment);
 
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 b45abeda284522f6bda8d51103d0b086b674529f..bcd8c7f39fa30c4104f05c8bcd3b316d157e8be7 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
@@ -27,7 +27,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "inherits", kind = INTERNAL, parameterNames = {"x", "what", "which"}, behavior = PURE)
-public abstract class InheritsBuiltin extends RBuiltinNode {
+public abstract class InheritsBuiltin extends RBuiltinNode.Arg3 {
 
     @Child InheritsNode inheritsNode = InheritsNodeGen.create();
 
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 1984f96e016cd60f5814895e32139654c4b3b7c7..c595f2f99755209a0dd058d93023e12b10e665c8 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 
 @RBuiltin(name = "intToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-public abstract class IntToBits extends RBuiltinNode {
+public abstract class IntToBits extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(IntToBits.class);
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 2c391f761fb276dad10a7ba84cbcb2d15647c578..531147ade95d62163384d83c1b5c79f337ee2418 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 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 {
+public abstract class IntToUtf8 extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(IntToUtf8.class);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Interactive.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Interactive.java
index 55bf8f6b8c1b8d87a22533e736818476d4c1a7e1..ef734b838ba875c3bec6bb12c9b8be9ba28554fb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Interactive.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Interactive.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,7 +32,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 
 @RBuiltin(name = "interactive", kind = PRIMITIVE, parameterNames = {}, behavior = READS_STATE)
-public abstract class Interactive extends RBuiltinNode {
+public abstract class Interactive extends RBuiltinNode.Arg0 {
     @Specialization
     protected byte interactive() {
         return RRuntime.asLogical(RContext.getInstance().isInteractive());
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java
index 5b684d04ab5e9032648697951289e25fb1d1fd34..e355db172763768bbe7828ea0f4ee066d4f88e73 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Internal.java
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
  * visible.
  */
 @RBuiltin(name = ".Internal", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"call"}, nonEvalArgs = 0, behavior = COMPLEX)
-public abstract class Internal extends RBuiltinNode {
+public abstract class Internal extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(Internal.class);
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 55ec16e7d4e238195b4c80da059c9f524a5b9525..de675420cf23efa59e1529b5e7430101f841b3bb 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 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 {
+public abstract class Invisible extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(Invisible.class);
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 4666c8694d32c80d049331fc9ffc5b03e1433ba5..8599ff3cdf59235b5e1d89728dcf16114debbcfd 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 @RBuiltin(name = "isatty", kind = INTERNAL, parameterNames = {"con"}, behavior = PURE)
-public abstract class IsATTY extends RBuiltinNode {
+public abstract class IsATTY extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(IsATTY.class);
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 98b56846836bf1ee0edb4dc96e6ed098d974ae50..075d0dbb0345c8a8fbb981fac42b4732aa436adb 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
@@ -53,7 +53,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public class IsFiniteFunctions {
 
-    public abstract static class Adapter extends RBuiltinNode {
+    public abstract static class Adapter extends RBuiltinNode.Arg1 {
 
         @Child private GetDimAttributeNode getDims = GetDimAttributeNode.create();
         @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
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 48cc21c9563ce13f760332e53ca650e2e6a15229..dd4dab9a055702a74f81034f690083ba3f4096d6 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
@@ -29,7 +29,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 // from apply.c
 
 @RBuiltin(name = "islistfactor", kind = INTERNAL, parameterNames = {"x", "recursive"}, behavior = PURE)
-public abstract class IsListFactor extends RBuiltinNode {
+public abstract class IsListFactor extends RBuiltinNode.Arg2 {
 
     protected abstract static class IsListFactorInternal extends Node {
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsMethodsDispatchOn.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsMethodsDispatchOn.java
index 22f316102e814c4c4fc05860d39973dc5e37faec..0318822491f553b8d30a16681e9a13fc31d114af 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsMethodsDispatchOn.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsMethodsDispatchOn.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,7 +32,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 
 @RBuiltin(name = ".isMethodsDispatchOn", kind = PRIMITIVE, parameterNames = {}, behavior = READS_STATE)
-public abstract class IsMethodsDispatchOn extends RBuiltinNode {
+public abstract class IsMethodsDispatchOn extends RBuiltinNode.Arg0 {
 
     public abstract byte execute();
 
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 b2a9cb0863c4517052e9ab3c5ec3f39256ac6a94..c08de1b1f10abdba38904bb6e90c461d64b64727 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
@@ -54,7 +54,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "is.na", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class IsNA extends RBuiltinNode {
+public abstract class IsNA extends RBuiltinNode.Arg1 {
 
     @Child private IsNA recursiveIsNA;
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
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 d4939ab3a5e1d9e3e3688d6edfa20ed44bac55c5..231e1e43fe69f01ebc7698576731ebbfc4f4e396 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 
 @RBuiltin(name = "isS4", kind = PRIMITIVE, parameterNames = {"object"}, behavior = PURE)
-public abstract class IsS4 extends RBuiltinNode {
+public abstract class IsS4 extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(IsS4.class);
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
index cffe0507af3c86d87f17c6c31807d645794bbd95..9152317546763b55b0cce7c33366cf254e19dfe0 100644
--- 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
@@ -31,7 +31,7 @@ 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 {
+public abstract class IsSingle extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(IsSingle.class);
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 2c7aa8fd5226978d20f69fa7be19cce8d9bb5751..74152f23bf2199922819321a77e4e70350476f6c 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
@@ -68,7 +68,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
  */
 public class IsTypeFunctions {
 
-    protected abstract static class MissingAdapter extends RBuiltinNode {
+    protected abstract static class MissingAdapter extends RBuiltinNode.Arg1 {
 
         protected static Casts createCasts(Class<? extends MissingAdapter> extCls) {
             Casts casts = new Casts(extCls);
@@ -553,7 +553,7 @@ public class IsTypeFunctions {
     }
 
     @RBuiltin(name = "is.vector", kind = INTERNAL, parameterNames = {"x", "mode"}, behavior = PURE)
-    public abstract static class IsVector extends RBuiltinNode {
+    public abstract static class IsVector extends RBuiltinNode.Arg2 {
 
         private final ConditionProfile attrNull = ConditionProfile.createBinaryProfile();
         private final ConditionProfile attrEmpty = ConditionProfile.createBinaryProfile();
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 e9daf68f7103a75e89e2d1c471081e96b43f1ff1..4c098438beb3419d62b138551c798ec9f2a3084a 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
@@ -44,10 +44,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.BinaryCompare;
 
-@RBuiltin(name = "is.unsorted", kind = INTERNAL, parameterNames = {"x", "strictly"}, behavior = PURE)
 // TODO support strictly
 // TODO support lists
-public abstract class IsUnsorted extends RBuiltinNode {
+@RBuiltin(name = "is.unsorted", kind = INTERNAL, parameterNames = {"x", "strictly"}, behavior = PURE)
+public abstract class IsUnsorted extends RBuiltinNode.Arg2 {
 
     @Child private BinaryMapBooleanFunctionNode ge = new BinaryMapBooleanFunctionNode(BinaryCompare.GREATER_EQUAL.createOperation());
     @Child private BinaryMapBooleanFunctionNode gt = new BinaryMapBooleanFunctionNode(BinaryCompare.GREATER_THAN.createOperation());
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 5be9dfbdad803986bb42cdb760000c5bce9beaf5..76f62d8d8d2752017abd6323b7473c1189f3fd9b 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
@@ -13,9 +13,11 @@ package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.dimEq;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.dimGt;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gt;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.matrix;
 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.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.or;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.squareMatrix;
@@ -37,7 +39,7 @@ 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.Predef;
+import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNodeGen;
@@ -68,7 +70,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public class LaFunctions {
 
     @RBuiltin(name = "La_version", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class Version extends RBuiltinNode {
+    public abstract static class Version extends RBuiltinNode.Arg0 {
         @Child LapackRFFI.IlaverNode ilaverNode = RFFIFactory.getRFFI().getLapackRFFI().createIlaverNode();
 
         @Specialization
@@ -80,19 +82,17 @@ public class LaFunctions {
         }
     }
 
-    private abstract static class RsgRBuiltinNode extends RBuiltinNode {
-        protected static final String[] NAMES = new String[]{"values", "vectors"};
+    protected static final String[] NAMES = new String[]{"values", "vectors"};
 
-        protected static Casts createCasts(Class<? extends RsgRBuiltinNode> extClass) {
-            Casts casts = new Casts(extClass);
-            casts.arg("matrix").asDoubleVector(false, true, false).mustBe(squareMatrix(), Message.MUST_BE_SQUARE_NUMERIC, "x");
-            casts.arg("onlyValues").defaultError(Message.INVALID_ARGUMENT, "only.values").asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
-            return casts;
-        }
+    protected static Casts createCasts(Class<? extends RBuiltinNode> extClass) {
+        Casts casts = new Casts(extClass);
+        casts.arg("matrix").asDoubleVector(false, true, false).mustBe(squareMatrix(), Message.MUST_BE_SQUARE_NUMERIC, "x");
+        casts.arg("onlyValues").defaultError(Message.INVALID_ARGUMENT, "only.values").asLogicalVector().findFirst().mustNotBeNA().map(toBoolean());
+        return casts;
     }
 
     @RBuiltin(name = "La_rg", kind = INTERNAL, parameterNames = {"matrix", "onlyValues"}, behavior = PURE)
-    public abstract static class Rg extends RsgRBuiltinNode {
+    public abstract static class Rg extends RBuiltinNode.Arg2 {
 
         private final ConditionProfile hasComplexValues = ConditionProfile.createBinaryProfile();
 
@@ -192,7 +192,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_rs", kind = INTERNAL, parameterNames = {"matrix", "onlyValues"}, behavior = PURE)
-    public abstract static class Rs extends RsgRBuiltinNode {
+    public abstract static class Rs extends RBuiltinNode.Arg2 {
 
         static {
             createCasts(Rs.class);
@@ -253,7 +253,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_qr", kind = INTERNAL, parameterNames = {"in"}, behavior = PURE)
-    public abstract static class Qr extends RBuiltinNode {
+    public abstract static class Qr extends RBuiltinNode.Arg1 {
 
         @CompilationFinal private static final String[] NAMES = new String[]{"qr", "rank", "qraux", "pivot"};
 
@@ -301,7 +301,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "qr_coef_real", kind = INTERNAL, parameterNames = {"q", "b"}, behavior = PURE)
-    public abstract static class QrCoefReal extends RBuiltinNode {
+    public abstract static class QrCoefReal extends RBuiltinNode.Arg2 {
 
         private static final char SIDE = 'L';
         private static final char TRANS = 'T';
@@ -360,7 +360,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "det_ge_real", kind = INTERNAL, parameterNames = {"a", "uselog"}, behavior = PURE)
-    public abstract static class DetGeReal extends RBuiltinNode {
+    public abstract static class DetGeReal extends RBuiltinNode.Arg2 {
 
         private static final RStringVector NAMES_VECTOR = RDataFactory.createStringVector(new String[]{"modulus", "sign"}, RDataFactory.COMPLETE_VECTOR);
         private static final RStringVector DET_CLASS = RDataFactory.createStringVector(new String[]{"det"}, RDataFactory.COMPLETE_VECTOR);
@@ -442,7 +442,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_chol", kind = INTERNAL, parameterNames = {"a", "pivot", "tol"}, behavior = PURE)
-    public abstract static class LaChol extends RBuiltinNode {
+    public abstract static class LaChol extends RBuiltinNode.Arg3 {
 
         private final ConditionProfile noPivot = ConditionProfile.createBinaryProfile();
 
@@ -510,7 +510,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_chol2inv", kind = INTERNAL, parameterNames = {"a", "size"}, behavior = PURE)
-    public abstract static class LaChol2Inv extends RBuiltinNode {
+    public abstract static class LaChol2Inv extends RBuiltinNode.Arg2 {
 
         @Child private SetFixedAttributeNode setPivotAttrNode = SetFixedAttributeNode.create("pivot");
         @Child private SetFixedAttributeNode setRankAttrNode = SetFixedAttributeNode.create("rank");
@@ -518,7 +518,7 @@ public class LaFunctions {
         static {
             Casts casts = new Casts(LaChol2Inv.class);
             casts.arg("a").asDoubleVector(false, true, false).mustBe(matrix(), Message.MUST_BE_NUMERIC_MATRIX, "a");
-            casts.arg("size").asIntegerVector().mustBe(Predef.notEmpty()).findFirst().mustBe(Predef.gt(0), Message.MUST_BE_POSITIVE_INT);
+            casts.arg("size").asIntegerVector().mustBe(notEmpty()).findFirst().mustBe(gt(0), Message.MUST_BE_POSITIVE_INT);
         }
 
         @Specialization
@@ -559,7 +559,7 @@ public class LaFunctions {
     }
 
     @RBuiltin(name = "La_solve", kind = INTERNAL, parameterNames = {"a", "bin", "tolin"}, behavior = PURE)
-    public abstract static class LaSolve extends RBuiltinNode {
+    public abstract static class LaSolve extends RBuiltinNode.Arg3 {
         @Child private CastDoubleNode castDouble = CastDoubleNodeGen.create(false, false, false);
 
         private static Function<RAbstractDoubleVector, Object> getDimVal(int dim) {
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 c03cc95d031d4f9231600cb604d032d27eb35bf1..0e8c9f0639a7a21082dbdba6dcedeabae9d49cc4 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
@@ -64,7 +64,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  * See the comment in {@link VApply} regarding "...".
  */
 @RBuiltin(name = "lapply", kind = INTERNAL, parameterNames = {"X", "FUN"}, splitCaller = true, behavior = COMPLEX)
-public abstract class Lapply extends RBuiltinNode {
+public abstract class Lapply extends RBuiltinNode.Arg2 {
 
     private static final Source CALL_SOURCE = RSource.fromTextInternal("FUN(X[[i]], ...)", RSource.Internal.LAPPLY);
 
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 df92d3e9fa020cb62fbb1f1212cde43b66c9597d..2acf8880970607484d5a3a06dfd7ade019115ea1 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.nodes.control.RLengthNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "length", kind = PRIMITIVE, dispatch = INTERNAL_GENERIC, parameterNames = {"x"}, behavior = PURE)
-public abstract class Length extends RBuiltinNode {
+public abstract class Length extends RBuiltinNode.Arg1 {
 
     public abstract int executeInt(VirtualFrame frame, Object vector);
 
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 a9eb95fc4858247976bce2ae67ab22eb85bc2b06..69e7498c34e5ed7a06a1bc8be2d2797ba4b76620 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
@@ -46,7 +46,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "lengths", kind = INTERNAL, parameterNames = {"x", "use.names"}, behavior = PURE)
-public abstract class Lengths extends RBuiltinNode {
+public abstract class Lengths extends RBuiltinNode.Arg2 {
 
     @Child private RLengthNode lengthNode;
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/License.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/License.java
index 6c6bc4795b12f137bd2a551075b15748a73a3ba9..b98566310e2335a0f3afe3a2f291415913467458 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/License.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/License.java
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.conn.StdConnections;
 import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = "license", visibility = OFF, aliases = {"licence"}, kind = SUBSTITUTE, parameterNames = {}, behavior = IO)
-public abstract class License extends RBuiltinNode {
+public abstract class License extends RBuiltinNode.Arg0 {
 
     @Specialization
     @TruffleBoundary
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 f1ab5acbb72b74e7146af06404d35b25accf3af4..60a62338d6d531bb9243592afa0d452fc68309f1 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
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "list2env", kind = INTERNAL, parameterNames = {"x", "envir"}, behavior = PURE)
-public abstract class List2Env extends RBuiltinNode {
+public abstract class List2Env extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(List2Env.class);
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 e7ffa8d42c2de6915c99b212b0c5fb163ef5556a..dc16026b21480763d246b606c21b49e00d356ee1 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
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
 @RBuiltin(name = "list", kind = PRIMITIVE, parameterNames = {"..."}, behavior = PURE)
-public abstract class ListBuiltin extends RBuiltinNode {
+public abstract class ListBuiltin extends RBuiltinNode.Arg1 {
 
     protected static final int CACHE_LIMIT = 2;
     protected static final int MAX_SHARE_OBJECT_NODES = 16;
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 01788ee13c0a349a315295a28078545eb1c78d4c..9d7e4eec318c1bfc3eecdda2e843d47cff737805 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
@@ -30,7 +30,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.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.nodes.builtin.base.SerializeFunctions.Adapter;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -52,7 +51,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public class LoadSaveFunctions {
 
     @RBuiltin(name = "loadFromConn2", visibility = OFF, kind = INTERNAL, parameterNames = {"con", "envir", "verbose"}, behavior = IO)
-    public abstract static class LoadFromConn2 extends RBuiltinNode {
+    public abstract static class LoadFromConn2 extends RBuiltinNode.Arg3 {
 
         private final NACheck naCheck = NACheck.create();
 
@@ -110,7 +109,7 @@ public class LoadSaveFunctions {
     }
 
     @RBuiltin(name = "load", visibility = OFF, kind = INTERNAL, parameterNames = {"file", "envir"}, behavior = IO)
-    public abstract static class Load extends RBuiltinNode {
+    public abstract static class Load extends RBuiltinNode.Arg2 {
         // now deprecated but still used by some packages
 
         static {
@@ -186,7 +185,7 @@ public class LoadSaveFunctions {
     }
 
     @RBuiltin(name = "saveToConn", visibility = OFF, kind = INTERNAL, parameterNames = {"list", "con", "ascii", "version", "environment", "eval.promises"}, behavior = IO)
-    public abstract static class SaveToConn extends Adapter {
+    public abstract static class SaveToConn extends RBuiltinNode.Arg6 {
         private static final String ASCII_HEADER = "RDA2\n";
         private static final String XDR_HEADER = "RDX2\n";
 
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 4f043390f4c490b587188dedf3614f8d4bdf1011..aae947e9a61c705ef829d0a05a3e7835369b7eac 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
@@ -52,7 +52,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public class LocaleFunctions {
 
     @RBuiltin(name = "Sys.getlocale", kind = INTERNAL, parameterNames = {"category"}, behavior = READS_STATE)
-    public abstract static class GetLocale extends RBuiltinNode {
+    public abstract static class GetLocale extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(GetLocale.class);
@@ -90,7 +90,7 @@ public class LocaleFunctions {
     }
 
     @RBuiltin(name = "Sys.setlocale", kind = INTERNAL, parameterNames = {"category", "locale"}, behavior = MODIFIES_STATE)
-    public abstract static class SetLocale extends RBuiltinNode {
+    public abstract static class SetLocale extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(SetLocale.class);
@@ -107,7 +107,7 @@ public class LocaleFunctions {
     }
 
     @RBuiltin(name = "Sys.localeconv", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class LocaleConv extends RBuiltinNode {
+    public abstract static class LocaleConv extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected Object localeconv() {
@@ -117,7 +117,7 @@ public class LocaleFunctions {
     }
 
     @RBuiltin(name = "l10n_info", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class L10nInfo extends RBuiltinNode {
+    public abstract static class L10nInfo extends RBuiltinNode.Arg0 {
         private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"MBCS", "UTF-8", "Latin-1"}, RDataFactory.COMPLETE_VECTOR);
 
         @Specialization
@@ -132,7 +132,7 @@ public class LocaleFunctions {
     }
 
     @RBuiltin(name = "enc2native", kind = PRIMITIVE, parameterNames = "x", behavior = READS_STATE)
-    public abstract static class Enc2Native extends RBuiltinNode {
+    public abstract static class Enc2Native extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Enc2Native.class);
@@ -147,7 +147,7 @@ public class LocaleFunctions {
     }
 
     @RBuiltin(name = "enc2utf8", kind = PRIMITIVE, parameterNames = "x", behavior = READS_STATE)
-    public abstract static class Enc2Utf8 extends RBuiltinNode {
+    public abstract static class Enc2Utf8 extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Enc2Utf8.class);
@@ -162,7 +162,7 @@ public class LocaleFunctions {
     }
 
     @RBuiltin(name = "bindtextdomain", kind = PRIMITIVE, parameterNames = {"domain", "dirname"}, behavior = READS_STATE)
-    public abstract static class BindTextDomain extends RBuiltinNode {
+    public abstract static class BindTextDomain extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(BindTextDomain.class);
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 3bce1da46d8da0d6724df724d2f193a3aafe23df..628a8447547c09ec2af3c49711f97ed8d1a3f769 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
@@ -60,7 +60,7 @@ import java.util.function.Function;
 
 public class LogFunctions {
     @RBuiltin(name = "log", kind = PRIMITIVE, parameterNames = {"x", "base"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-    public abstract static class Log extends RBuiltinNode {
+    public abstract static class Log extends RBuiltinNode.Arg2 {
 
         private final NAProfile naX = NAProfile.create();
         private final BranchProfile nanProfile = BranchProfile.create();
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 f2323827fc7f0e8f1b047af011edd8e9b8dc750d..275ed1e26c715156191fea647c77b5260195d167 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
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 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 {
+public abstract class Ls extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(Ls.class);
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 127213345757df147763a33c7efddffbfd8b4670..0a382c92aa67d8b806d07d425eaf9e5e96b133a4 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "make.names", kind = INTERNAL, parameterNames = {"names", "allow_"}, behavior = PURE)
-public abstract class MakeNames extends RBuiltinNode {
+public abstract class MakeNames extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile namesLengthZero = ConditionProfile.createBinaryProfile();
     private final NACheck dummyCheck = NACheck.create(); // never triggered (used for vector update)
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 6fd3a0fecadfa5d77d7eeb51a88ba0d8c3981296..eddadcd858b150cc4ee5544107aed1931bcb23dd 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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "make.unique", kind = INTERNAL, parameterNames = {"names", "sep"}, behavior = PURE)
-public abstract class MakeUnique extends RBuiltinNode {
+public abstract class MakeUnique extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile namesProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile duplicatesProfile = ConditionProfile.createBinaryProfile();
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 f51a45e0d95e883c1f8039ad0b950dd30f8a2e07..e649410a8914d9aa6c9bffc3cd69e3e41c9960b0 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
@@ -35,25 +35,23 @@ import com.oracle.truffle.api.nodes.Node;
 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.access.vector.ElementAccessMode;
+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.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;
 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.RLogicalVector;
+import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.nodes.InternalRSyntaxNodeChildren;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
@@ -64,7 +62,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  * the longest vector, with the usual recycling rule.
  */
 @RBuiltin(name = "mapply", kind = INTERNAL, parameterNames = {"FUN", "dots", "MoreArgs"}, splitCaller = true, behavior = COMPLEX)
-public abstract class Mapply extends RBuiltinNode {
+public abstract class Mapply extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(Mapply.class);
@@ -78,7 +76,7 @@ public abstract class Mapply extends RBuiltinNode {
 
     protected static final class ElementNode extends Node {
         @Child private Length lengthNode;
-        @Child private Subscript indexedLoadNode;
+        @Child private ExtractVectorNode extractNode;
         @Child private WriteVariableNode writeVectorElementNode;
         private final String vectorElementName;
         private final String argName;
@@ -87,7 +85,7 @@ public abstract class Mapply extends RBuiltinNode {
             // the name is a hack to treat ReadVariableNode-s as syntax nodes
             this.vectorElementName = "*" + AnonymousFrameVariable.create(vectorElementName);
             this.lengthNode = insert(LengthNodeGen.create());
-            this.indexedLoadNode = insert(SubscriptNodeGen.create());
+            this.extractNode = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, false));
             this.writeVectorElementNode = insert(WriteVariableNode.createAnonymous(this.vectorElementName, Mode.REGULAR, null));
             this.argName = argName;
         }
@@ -110,8 +108,6 @@ public abstract class Mapply extends RBuiltinNode {
     public abstract static class MapplyInternalNode extends Node implements InternalRSyntaxNodeChildren {
 
         private static final String VECTOR_ELEMENT_PREFIX = "MAPPLY_VEC_ELEM_";
-        private static final RLogicalVector DROP = RDataFactory.createLogicalVectorFromScalar(true);
-        private static final RLogicalVector EXACT = RDataFactory.createLogicalVectorFromScalar(true);
         private static final ArgumentsSignature I_INDEX = ArgumentsSignature.get("i");
         private static final RArgsValuesAndNames[] INDEX_CACHE = new RArgsValuesAndNames[32];
 
@@ -125,33 +121,8 @@ public abstract class Mapply extends RBuiltinNode {
 
         public abstract Object[] execute(VirtualFrame frame, RAbstractListVector dots, RFunction function, RAbstractListVector additionalArguments);
 
-        private static Object getVecElement(VirtualFrame frame, RAbstractListVector dots, int i, int listIndex, int[] lengths, Subscript indexedLoadNode) {
-            Object listElem = dots.getDataAt(listIndex);
-            RAbstractContainer vec = null;
-            if (listElem instanceof RAbstractContainer) {
-                vec = (RAbstractContainer) listElem;
-            } else {
-                // TODO scalar types are a nuisance!
-                if (listElem instanceof String) {
-                    vec = RDataFactory.createStringVectorFromScalar((String) listElem);
-                } else if (listElem instanceof Integer) {
-                    vec = RDataFactory.createIntVectorFromScalar((int) listElem);
-                } else if (listElem instanceof Double) {
-                    vec = RDataFactory.createDoubleVectorFromScalar((double) listElem);
-                } else {
-                    throw RInternalError.unimplemented();
-                }
-            }
-
-            int adjIndex = i % lengths[listIndex];
-            RArgsValuesAndNames indexArg;
-            if (adjIndex < INDEX_CACHE.length) {
-                indexArg = INDEX_CACHE[adjIndex];
-            } else {
-                indexArg = new RArgsValuesAndNames(new Object[]{adjIndex + 1}, I_INDEX);
-            }
-            return indexedLoadNode.executeBuiltin(frame, vec, indexArg, EXACT, DROP);
-
+        private static Object getVecElement(VirtualFrame frame, RAbstractListVector dots, int i, int listIndex, int[] lengths, ExtractVectorNode extractNode) {
+            return extractNode.apply(frame, dots.getDataAt(listIndex), new Object[]{i % lengths[listIndex] + 1}, RLogical.TRUE, RLogical.TRUE);
         }
 
         @SuppressWarnings("unused")
@@ -183,7 +154,7 @@ public abstract class Mapply extends RBuiltinNode {
             for (int i = 0; i < maxLength; i++) {
                 /* Evaluate and store the arguments */
                 for (int listIndex = 0; listIndex < dotsLength; listIndex++) {
-                    Object vecElement = getVecElement(frame, dots, i, listIndex, lengths, cachedElementNodeArray[listIndex].indexedLoadNode);
+                    Object vecElement = getVecElement(frame, dots, i, listIndex, lengths, cachedElementNodeArray[listIndex].extractNode);
                     cachedElementNodeArray[listIndex].writeVectorElementNode.execute(frame, vecElement);
                 }
                 /* Now call the function */
@@ -195,7 +166,7 @@ public abstract class Mapply extends RBuiltinNode {
         @Specialization(replaces = "cachedMApply")
         protected Object[] mApply(VirtualFrame frame, RAbstractListVector dots, RFunction function, RAbstractListVector moreArgs,
                         @Cached("create()") RLengthNode lengthNode,
-                        @Cached("createIndexedLoadNode()") Subscript indexedLoadNode,
+                        @Cached("createExtractNode()") ExtractVectorNode extractNode,
                         @Cached("create()") RExplicitCallNode callNode) {
             int dotsLength = dots.getLength();
             int moreArgsLength = moreArgs.getLength();
@@ -226,7 +197,7 @@ public abstract class Mapply extends RBuiltinNode {
             for (int i = 0; i < maxLength; i++) {
                 /* Evaluate and store the arguments */
                 for (int listIndex = 0; listIndex < dotsLength; listIndex++) {
-                    Object vecElement = getVecElement(frame, dots, i, listIndex, lengths, indexedLoadNode);
+                    Object vecElement = getVecElement(frame, dots, i, listIndex, lengths, extractNode);
                     values[listIndex] = vecElement;
                 }
                 /* Now call the function */
@@ -265,8 +236,8 @@ public abstract class Mapply extends RBuiltinNode {
             return elementNodes;
         }
 
-        protected Subscript createIndexedLoadNode() {
-            return SubscriptNodeGen.create();
+        protected ExtractVectorNode createExtractNode() {
+            return ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, false);
         }
 
         protected boolean sameNames(RAbstractListVector list, RAbstractListVector cachedList) {
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 d6baac0ef1d1b6e776f1de897afa039adf15aa30..1321af4d0cebde99a813941ce1a431b947371831 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
@@ -62,7 +62,7 @@ import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "%*%", kind = PRIMITIVE, parameterNames = {"", ""}, behavior = PURE)
-public abstract class MatMult extends RBuiltinNode {
+public abstract class MatMult extends RBuiltinNode.Arg2 {
 
     private static final int BLOCK_SIZE = 64;
 
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 9c984f8551376887dfd62238f78b6f04c5fd05f5..e15199525e6b3b4539b9374e9f9fe21b2248220c 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
@@ -68,7 +68,7 @@ import com.oracle.truffle.r.runtime.ops.na.NAProfile;
  * TODO: handle "incomparables" parameter.
  */
 @RBuiltin(name = "match", kind = INTERNAL, parameterNames = {"x", "table", "nomatch", "incomparables"}, behavior = PURE)
-public abstract class Match extends RBuiltinNode {
+public abstract class Match extends RBuiltinNode.Arg4 {
 
     protected abstract Object executeRIntVector(Object x, Object table, Object noMatch, Object incomparables);
 
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 b9d9c1f7c5aa787a8faea98d079b75a77ad7403a..f672ab2914dfaac95b2ebd9dedb89f9ae0545514 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
@@ -63,7 +63,7 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 @RBuiltin(name = "match.arg", kind = SUBSTITUTE, parameterNames = {"arg", "choices", "several.ok"}, nonEvalArgs = {0}, behavior = COMPLEX)
-public abstract class MatchArg extends RBuiltinNode {
+public abstract class MatchArg extends RBuiltinNode.Arg3 {
 
     static {
         Casts.noCasts(MatchArg.class);
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 5c0d083ede6ab13641b96de7e274e3825bc40883..00ba7a002e1d50f9bdce1032ff260260630b6d7d 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
@@ -58,7 +58,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 @RBuiltin(name = "match.fun", kind = SUBSTITUTE, parameterNames = {"fun", "descend"}, nonEvalArgs = 0, behavior = COMPLEX)
-public abstract class MatchFun extends RBuiltinNode {
+public abstract class MatchFun extends RBuiltinNode.Arg2 {
 
     @Override
     public Object[] getDefaultParameterValues() {
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 feb1059c091aed2411f32284e9520baad72522c4..161972a2025762f48eb886d98d443d34169fd7e2 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "matrix", kind = INTERNAL, parameterNames = {"data", "nrow", "ncol", "byrow", "dimnames", "missingNr", "missingNc"}, behavior = PURE)
-public abstract class Matrix extends RBuiltinNode {
+public abstract class Matrix extends RBuiltinNode.Arg7 {
 
     @Child private Transpose transpose;
     @Child private UpdateDimNames updateDimNames;
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 2e898cf52915435168f803976d8ac0e8abf10098..6c3556db61b99058eb0ce292cdc5ea1522b12b79 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 
 @RBuiltin(name = "max", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
-public abstract class Max extends RBuiltinNode {
+public abstract class Max extends RBuiltinNode.Arg2 {
 
     private static final ReduceSemantics semantics = new ReduceSemantics(RRuntime.INT_MIN_VALUE, Double.NEGATIVE_INFINITY, false, RError.Message.NO_NONMISSING_MAX,
                     RError.Message.NO_NONMISSING_MAX_NA, false, true);
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 dc04a0b92877a108aaf3d35057386b54bf16a0c8..3cd1cf689cf244c73adb9abffd2365191b523a40 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 
 @RBuiltin(name = "mean", kind = INTERNAL, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class Mean extends RBuiltinNode {
+public abstract class Mean extends RBuiltinNode.Arg1 {
 
     private final BranchProfile emptyProfile = BranchProfile.create();
 
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 530074e8754e24dfe05de673763557cf652eef8b..c2ededbc786e8ec0835efb45edd40b2f4176718c 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
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
  * Note: invoked from merge.data.frame.
  */
 @RBuiltin(name = "merge", kind = INTERNAL, parameterNames = {"xinds", "yinds", "all.x", "all.y"}, behavior = PURE)
-public abstract class Merge extends RBuiltinNode {
+public abstract class Merge extends RBuiltinNode.Arg4 {
 
     static {
         Casts casts = new Casts(Merge.class);
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 09b73c273d4219428e837d870bca7555e078fdb5..1f14fbafc416a9542bbf07fbae9a57a5055ff25b 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 
 @RBuiltin(name = "min", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
-public abstract class Min extends RBuiltinNode {
+public abstract class Min extends RBuiltinNode.Arg2 {
 
     private static final ReduceSemantics semantics = new ReduceSemantics(RRuntime.INT_MAX_VALUE, Double.POSITIVE_INFINITY, false, RError.Message.NO_NONMISSING_MIN,
                     RError.Message.NO_NONMISSING_MIN_NA, false, true);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
index 64f1c93b5832a698c81a03fe9259718f8c828b28..355b1f84a311a425b20bae054bd485b132442398 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
  * correctly, because the varargs are already handled by the argument matching.
  */
 @RBuiltin(name = "missing", kind = PRIMITIVE, nonEvalArgs = 0, parameterNames = {"x"}, behavior = COMPLEX)
-public abstract class Missing extends RBuiltinNode {
+public abstract class Missing extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Missing.class);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NArgs.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NArgs.java
index 6a166f0a124262961f583bac969c032b8af4936a..06edb6da08b1a31a0b462cb3e025b85c35a702a5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NArgs.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NArgs.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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 
 // TODO Figure out how to distinguish f(,,a) from f(a) - RMissing is used in both contexts
 @RBuiltin(name = "nargs", kind = PRIMITIVE, parameterNames = {}, behavior = RBehavior.READS_FRAME)
-public abstract class NArgs extends RBuiltinNode {
+public abstract class NArgs extends RBuiltinNode.Arg0 {
 
     private final BranchProfile isPromiseProfile = BranchProfile.create();
 
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 7f3e1055f3507961d15d994ce5537180908f8d3f..8c6b7d81d146cc79ab669752db13765b6742b111 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
@@ -51,7 +51,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 // TODO interpret "type" and "allowNA" arguments
 @RBuiltin(name = "nchar", kind = INTERNAL, parameterNames = {"x", "type", "allowNA", "keepNA"}, behavior = PURE)
-public abstract class NChar extends RBuiltinNode {
+public abstract class NChar extends RBuiltinNode.Arg4 {
     private static final String[] TYPES = new String[]{"bytes", "chars", "width"};
     private static final int TYPE_BYTES = 0;
     private static final int TYPE_CHARS = 1;
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 d72cda8937c3980ac6688c9fa9fa908234c52a48..b3959ceda785fe66167eb2edbc0e146ec80ee042 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "ngettext", kind = INTERNAL, parameterNames = {"n", "msg1", "msg2", "domain"}, behavior = COMPLEX)
-public abstract class NGetText extends RBuiltinNode {
+public abstract class NGetText extends RBuiltinNode.Arg4 {
 
     static {
         Casts casts = new Casts(NGetText.class);
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 b8ec8ffd1b487ad81bffaa89f5e36818e70b0b01..741fd707d609a55def54d55a22ea9f646e9fb288 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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 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 {
+public abstract class NZChar extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(NZChar.class);
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 cbce750d0918da1af2b72833f68f41a90336de89..1bdd1932b9b9e3fc56a7fd98ec481917fb3f0325 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
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @ImportStatic({RRuntime.class, com.oracle.truffle.api.interop.Message.class})
 @RBuiltin(name = "names", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class Names extends RBuiltinNode {
+public abstract class Names extends RBuiltinNode.Arg1 {
 
     private final ConditionProfile hasNames = ConditionProfile.createBinaryProfile();
     @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create();
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 b91bffd815d3834eeffa726bb175172cff31661f..6c3e1267f3eb3ea8a561ed6083059a903b88a6bc 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
@@ -50,7 +50,7 @@ public class NamespaceFunctions {
     }
 
     @RBuiltin(name = "getRegisteredNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = READS_STATE)
-    public abstract static class GetRegisteredNamespace extends RBuiltinNode {
+    public abstract static class GetRegisteredNamespace extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(GetRegisteredNamespace.class);
@@ -79,7 +79,7 @@ public class NamespaceFunctions {
     }
 
     @RBuiltin(name = "isRegisteredNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = READS_STATE)
-    public abstract static class IsRegisteredNamespace extends RBuiltinNode {
+    public abstract static class IsRegisteredNamespace extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(IsRegisteredNamespace.class);
@@ -108,7 +108,7 @@ public class NamespaceFunctions {
     }
 
     @RBuiltin(name = "isNamespaceEnv", kind = INTERNAL, parameterNames = {"env"}, behavior = PURE)
-    public abstract static class IsNamespaceEnv extends RBuiltinNode {
+    public abstract static class IsNamespaceEnv extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(IsNamespaceEnv.class);
@@ -126,7 +126,7 @@ public class NamespaceFunctions {
     }
 
     @RBuiltin(name = "getNamespaceRegistry", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class GetNamespaceRegistry extends RBuiltinNode {
+    public abstract static class GetNamespaceRegistry extends RBuiltinNode.Arg0 {
         @Specialization
         protected REnvironment doGetNamespaceRegistry() {
             return REnvironment.getNamespaceRegistry();
@@ -134,7 +134,7 @@ public class NamespaceFunctions {
     }
 
     @RBuiltin(name = "registerNamespace", kind = INTERNAL, parameterNames = {"name", "env"}, behavior = MODIFIES_STATE)
-    public abstract static class RegisterNamespace extends RBuiltinNode {
+    public abstract static class RegisterNamespace extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(RegisterNamespace.class);
@@ -161,7 +161,7 @@ public class NamespaceFunctions {
     }
 
     @RBuiltin(name = "unregisterNamespace", kind = INTERNAL, parameterNames = {"name"}, behavior = MODIFIES_STATE)
-    public abstract static class UnregisterNamespace extends RBuiltinNode {
+    public abstract static class UnregisterNamespace extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(UnregisterNamespace.class);
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 501f00d7cc053d5839827fe0a516469e23e717ec..a046161d57def32b221be0bfeba86bd3e748b70f 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
@@ -48,7 +48,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "normalizePath", kind = INTERNAL, parameterNames = {"path", "winslash", "mustwork"}, behavior = IO)
-public abstract class NormalizePath extends RBuiltinNode {
+public abstract class NormalizePath extends RBuiltinNode.Arg3 {
 
     private final ConditionProfile doesNotNeedToWork = ConditionProfile.createBinaryProfile();
 
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 26a9bc602f80816b142a1cc48a126f4931a60ad7..c540de96876e1e0f56e5c95b70328fa1988ebc5d 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
@@ -46,7 +46,7 @@ public class NumericalFunctions {
      * specialization, which would trigger the code generation performed by the annotation
      * processor.
      */
-    public abstract static class DummyNode extends RBuiltinNode {
+    public abstract static class DummyNode extends RBuiltinNode.Arg1 {
 
         @Specialization
         protected Object dummySpec(@SuppressWarnings("unused") Object value) {
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 2eb897b4f8c21c4ec258d4a7ed501fec7358428e..c1bc7253e3734145ae3e0e57a2c8927f41f6cbe0 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.env.frame.RFrameSlot;
 
 @RBuiltin(name = "on.exit", visibility = OFF, kind = PRIMITIVE, parameterNames = {"expr", "add"}, nonEvalArgs = 0, behavior = COMPLEX)
-public abstract class OnExit extends RBuiltinNode {
+public abstract class OnExit extends RBuiltinNode.Arg2 {
 
     @CompilationFinal private FrameSlot onExitSlot;
 
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 11140af453f8253fefd67abbad5ae1221d291fc0..f79c0a4863229b0c2c95824a014272c403e26b2d 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
@@ -57,7 +57,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public class OptionsFunctions {
 
     @RBuiltin(name = "options", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"..."}, behavior = MODIFIES_STATE)
-    public abstract static class Options extends RBuiltinNode {
+    public abstract static class Options extends RBuiltinNode.Arg1 {
 
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
@@ -190,7 +190,7 @@ public class OptionsFunctions {
     }
 
     @RBuiltin(name = "getOption", kind = INTERNAL, parameterNames = "x", behavior = READS_STATE)
-    public abstract static class GetOption extends RBuiltinNode {
+    public abstract static class GetOption extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(GetOption.class);
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 b9e0292d518bc565484f4fef5dae9966c8e2dbf5..56edbde21bfcb951cc63a5704dfa59951b95d8a1 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "pmatch", kind = INTERNAL, parameterNames = {"x", "table", "nomatch", "duplicates.ok"}, behavior = PURE)
-public abstract class PMatch extends RBuiltinNode {
+public abstract class PMatch extends RBuiltinNode.Arg4 {
 
     private final ConditionProfile nomatchNA = ConditionProfile.createBinaryProfile();
 
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 28fec92997b4f26871c4ba1c1d0a0ea3546479ef..4b9aed674aeec3fa423d9024b4bf5673216ed6ca 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
@@ -66,7 +66,7 @@ import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmeticFactory;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
-public abstract class PMinMax extends RBuiltinNode {
+public abstract class PMinMax extends RBuiltinNode.Arg2 {
 
     @Child private MultiElemStringHandler stringHandler;
     @Child private CastToVectorNode castVector;
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 f4f37e8495139f6c66f6779953fb4621c3e7b984..b351ea5aefea8f9e5971fd50a297d0f218430b6f 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
@@ -91,7 +91,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * On the R side, GnuR adds similar R attributes to the result, which is important for R tooling.
  */
 @RBuiltin(name = "parse", kind = INTERNAL, parameterNames = {"conn", "n", "text", "prompt", "srcfile", "encoding"}, behavior = IO)
-public abstract class Parse extends RBuiltinNode {
+public abstract class Parse extends RBuiltinNode.Arg6 {
     @Child private CastIntegerNode castIntNode;
     @Child private CastStringNode castStringNode;
     @Child private CastToVectorNode castVectorNode;
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 36bbd68139e34809e071809b629af89fa1feba06..dfe638618325ae44cdca002c952443be28f8a070 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
@@ -52,7 +52,7 @@ 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 {
+public abstract class Paste extends RBuiltinNode.Arg3 {
 
     private static final String[] ONE_EMPTY_STRING = new String[]{""};
 
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 c00334447c68e3f0ddf4fd9a95687a6fa26a7c91..6b18011d046d0d454fad7482cfd01cfa149c53eb 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RList;
  * efficient.
  */
 @RBuiltin(name = "paste0", kind = INTERNAL, parameterNames = {"list", "collapse"}, behavior = PURE)
-public abstract class Paste0 extends RBuiltinNode {
+public abstract class Paste0 extends RBuiltinNode.Arg2 {
 
     @Child private Paste pasteNode = PasteNodeGen.create();
 
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 fe07eed30f65a47f88c8d9eb8c39e3d4ced3f71c..280c627acb8b4b5b4a5453530f47ecde37d92a14 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
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 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 {
+public abstract class PathExpand extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(PathExpand.class);
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 01bdd569f5cb076bf063b2fc7b2ea47f037545b6..f44ff63f51a6af10e960ba1fefe0eef72d278c69 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 
 @RBuiltin(name = "pretty", kind = INTERNAL, parameterNames = {"l", "u", "n", "min.n", "shrink.sml", "hi", "eps.correct"}, behavior = PURE)
-public abstract class Pretty extends RBuiltinNode {
+public abstract class Pretty extends RBuiltinNode.Arg7 {
 
     private static final RStringVector NAMES = RDataFactory.createStringVector(new String[]{"l", "u", "n"}, RDataFactory.COMPLETE_VECTOR);
 
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 3845cc9588dfb78e03e4180e4e7d3c2641cf21b1..3dcea15589c1caa75e692575d74107077b8c9f2d 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RFunction;
 
 @RBuiltin(name = ".Primitive", kind = PRIMITIVE, parameterNames = "name", behavior = PURE)
-public abstract class Primitive extends RBuiltinNode {
+public abstract class Primitive extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Primitive.class);
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 6f4906fe555703e2f47ae0d5352b39a83072a1fb..873b10c3c1e1777b846da88ff8d5d53e37c9ea5f 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
@@ -52,7 +52,7 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
 public class PrintFunctions {
 
     @RBuiltin(name = "print.default", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "digits", "quote", "na.print", "print.gap", "right", "max", "useSource", "noOpt"}, behavior = IO)
-    public abstract static class PrintDefault extends RBuiltinNode {
+    public abstract static class PrintDefault extends RBuiltinNode.Arg9 {
 
         @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create();
 
@@ -106,7 +106,7 @@ public class PrintFunctions {
     }
 
     @RBuiltin(name = "print.function", visibility = OFF, kind = INTERNAL, parameterNames = {"x", "useSource", "..."}, behavior = IO)
-    public abstract static class PrintFunction extends RBuiltinNode {
+    public abstract static class PrintFunction extends RBuiltinNode.Arg3 {
 
         @Child private ValuePrinterNode valuePrinter = new ValuePrinterNode();
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
index 24496e3ae2d465157530b90cb0d3a2f76122ff08..2492d86ee9d3acec7bd559b9879621153f621409 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
@@ -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.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
 @RBuiltin(name = "proc.time", kind = PRIMITIVE, parameterNames = {}, behavior = IO)
-public abstract class ProcTime extends RBuiltinNode {
+public abstract class ProcTime extends RBuiltinNode.Arg0 {
 
     private static final String[] NAMES = new String[]{"user.self", "sys.self", "elapsed", "user.child", "sys.child"};
     private static final RStringVector PROC_TIME_CLASS = RDataFactory.createStringVectorFromScalar("proc_time");
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 34cd247dd9fab8a929279795a2d7d733793c1688..e9c8a1a3067e9b1f158b8e27e888ad25ce14874c 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 
 @RBuiltin(name = "prod", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
-public abstract class Prod extends RBuiltinNode {
+public abstract class Prod extends RBuiltinNode.Arg2 {
 
     // TODO: handle multiple arguments, handle na.rm
 
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 c696b7bd654607cec8e61a40ba5924e8f117534d..8a2811b1f8b0991c80abc5750791d163f8505e2d 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
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
-public abstract class Quantifier extends RBuiltinNode {
+public abstract class Quantifier extends RBuiltinNode.Arg2 {
     protected static final int MAX_CACHED_LENGTH = 10;
 
     private final NACheck naCheck = NACheck.create();
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 d3e1003add778ffe5daade76241f83a7c0f8a218..9d9aa1803a2339befd7fb842563c88c81b026a7b 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
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.runtime.context.RContext;
 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 {
+public abstract class Quit extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(Quit.class);
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 a43472d12fc9bb7180a246818f4890201bc5c006..9daaa44d052386fb4e39e265e6f5c2416a3edfe2 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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 
 @RBuiltin(name = "quote", nonEvalArgs = 0, kind = PRIMITIVE, parameterNames = {"expr"}, behavior = PURE)
-public abstract class Quote extends RBuiltinNode {
+public abstract class Quote extends RBuiltinNode.Arg1 {
 
     protected static final int LIMIT = 3;
 
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 8abbd12d7a54e58e53741b57883d8df3db0e0d93..146b768b00d6e5e06d36ed4f3d07fb6438f9ec89 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
@@ -46,7 +46,7 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
 
 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 {
+    public abstract static class SetSeed extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(SetSeed.class);
@@ -76,7 +76,7 @@ public class RNGFunctions {
     }
 
     @RBuiltin(name = "RNGkind", kind = INTERNAL, parameterNames = {"kind", "normkind"}, behavior = MODIFIES_STATE)
-    public abstract static class RNGkind extends RBuiltinNode {
+    public abstract static class RNGkind extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(RNGkind.class);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RVersion.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RVersion.java
index 53e566ab53d8bf98d87755dc076fcfbefb984e12..5deeb4662eddf0329a88478afd547eee3a3fcdbf 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RVersion.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RVersion.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,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 
 @RBuiltin(name = "Version", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-public abstract class RVersion extends RBuiltinNode {
+public abstract class RVersion extends RBuiltinNode.Arg0 {
 
     @Specialization
     @TruffleBoundary
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 72ab6ad5c7e4227fd90998c13f5f7ed3825a0e0f..f80721c116078771e8f6c3d76fc83e37d56d96b1 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 
 @RBuiltin(name = "range", kind = PRIMITIVE, parameterNames = {"...", "na.rm", "finite"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
-public abstract class Range extends RBuiltinNode {
+public abstract class Range extends RBuiltinNode.Arg3 {
 
     private static final ReduceSemantics minSemantics = new ReduceSemantics(RRuntime.INT_MAX_VALUE, Double.POSITIVE_INFINITY, false, RError.Message.NO_NONMISSING_MIN,
                     RError.Message.NO_NONMISSING_MIN_NA, false, true);
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 19ba2180411cf4aaf825813cef365a70d10f6c16..c15016ffb9bde4c2dc0f275de2ff1e4e00574c51 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "rank", kind = INTERNAL, parameterNames = {"x", "len", "ties.method"}, behavior = PURE)
-public abstract class Rank extends RBuiltinNode {
+public abstract class Rank extends RBuiltinNode.Arg3 {
 
     @Child private Order.OrderVector1Node orderVector1Node;
     @Child private Order.CmpNode orderCmpNode;
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 74712ceaebf0de4b963f48332cc69430792c8340..f1fc024fe923095495b1959baa8b14c0fe235187 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public class RawFunctions {
 
     @RBuiltin(name = "charToRaw", kind = INTERNAL, parameterNames = "x", behavior = PURE)
-    public abstract static class CharToRaw extends RBuiltinNode {
+    public abstract static class CharToRaw extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(CharToRaw.class);
@@ -72,7 +72,7 @@ public class RawFunctions {
     }
 
     @RBuiltin(name = "rawToChar", kind = INTERNAL, parameterNames = {"x", "multiple"}, behavior = PURE)
-    public abstract static class RawToChar extends RBuiltinNode {
+    public abstract static class RawToChar extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(RawToChar.class);
@@ -106,7 +106,7 @@ public class RawFunctions {
     }
 
     @RBuiltin(name = "rawShift", kind = INTERNAL, parameterNames = {"x", "n"}, behavior = PURE)
-    public abstract static class RawShift extends RBuiltinNode {
+    public abstract static class RawShift extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(RawShift.class);
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 389eb9cbc4f2f8fd79bda46a0a150ec1df690c57..3afe3566f550717f1ebf1ee311c4e129a4659027 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 
 @RBuiltin(name = "rawToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-public abstract class RawToBits extends RBuiltinNode {
+public abstract class RawToBits extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(RawToBits.class);
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 c00909740507b49062fb6171f6ee7abfc285752e..7b259a032417427dcf6ccadc1215beee3ae44117 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 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 {
+public abstract class ReadDCF extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(ReadDCF.class);
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 06145344177eb6ff5c930bafba878adbe7a8225c..c39fa3a1b6f7ff4669953c543aaf40396f4ef25a 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 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 {
+public abstract class ReadREnviron extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(ReadREnviron.class);
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 bc5411859c8e3aff340dd5a79000ae01c4e690ff..f5d72cb3b60930338de975a7ebcd8e7a0a3e3862 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 @RBuiltin(name = "readline", kind = INTERNAL, parameterNames = "prompt", behavior = IO)
-public abstract class Readline extends RBuiltinNode {
+public abstract class Readline extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Readline.class);
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 6d88f338e46c7ab3f8a1bd063865c9624368ecb1..5d82e00576a4c32e52906c736c729abb2a467f56 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
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
  * The {@code Recall} {@code .Internal}.
  */
 @RBuiltin(name = "Recall", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"..."}, nonEvalArgs = {0}, behavior = COMPLEX)
-public abstract class Recall extends RBuiltinNode {
+public abstract class Recall extends RBuiltinNode.Arg1 {
 
     @Child private LocalReadVariableNode readArgs = LocalReadVariableNode.create(ArgumentsSignature.VARARG_NAME, false);
 
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 5182327ab41aeac25c16cefd9204729f11e4dc36..90b72ab45c609ecbe571b1c436e4762bc55f5451 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  * the recording like GnuR does.
  */
 @RBuiltin(name = "recordGraphics", kind = INTERNAL, parameterNames = {"expr", "list", "env"}, behavior = COMPLEX)
-public abstract class RecordGraphics extends RBuiltinNode {
+public abstract class RecordGraphics extends RBuiltinNode.Arg3 {
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
     @Child private RList2EnvNode list2EnvNode = new RList2EnvNode();
 
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 88bd9e9c800de9790d587d89d327064b6e72c707..bade5694f1ec24673a3a70fd5184dd1b2d2d6298 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 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 {
+public abstract class RegFinalizer extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(RegFinalizer.class);
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 2da580ca1226298c542cb94060104a06e1645687..cd00bcf9571c1074095466d0a3101951dc6e2ab2 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
@@ -87,7 +87,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * </ol>
  */
 @RBuiltin(name = "rep", kind = PRIMITIVE, parameterNames = {"x", "..."}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class Repeat extends RBuiltinNode {
+public abstract class Repeat extends RBuiltinNode.Arg2 {
 
     private static final PipelineBuilder PB_TIMES;
     private static final PipelineBuilder PB_LENGTH_OUT;
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 a9a9c80e8a953d11c94043b17f50bd23ac3a628b..3c27d15d99346612ad8612903740cdf656bb352a 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
@@ -53,7 +53,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "rep.int", kind = INTERNAL, parameterNames = {"x", "times"}, behavior = PURE)
-public abstract class RepeatInternal extends RBuiltinNode {
+public abstract class RepeatInternal extends RBuiltinNode.Arg2 {
 
     private final ConditionProfile timesOneProfile = ConditionProfile.createBinaryProfile();
 
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 da12e4f3b160c491e7524bd72e6047fa9b4460f8..91f3883d1e6ee06c3d2c4ae1e02c761aa660b6c2 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 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 {
+public abstract class RepeatLength extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(RepeatLength.class);
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 e990562976c17c4c4e23cf86f72bdc64776dde0d..643ac7f8f9659f1420067d7a994ecc200b1730fa 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
@@ -66,7 +66,7 @@ final class ReturnSpecial extends RNode {
  * {@link FunctionDefinitionNode}.
  */
 @RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX, nonEvalArgs = {0})
-public abstract class Return extends RBuiltinNode {
+public abstract class Return extends RBuiltinNode.Arg1 {
 
     public static RNode createSpecial(@SuppressWarnings("unused") ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) {
         return arguments.length == 1 ? new ReturnSpecial(arguments[0]) : null;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rhome.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rhome.java
index 2a735cdb0a6479d47ba055c05c72fa919b364a7e..e538405b680c0171efc9ed33d475eb374a9383b1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rhome.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rhome.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,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
  * R.home builtin.
  */
 @RBuiltin(name = "R.home", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-public abstract class Rhome extends RBuiltinNode {
+public abstract class Rhome extends RBuiltinNode.Arg0 {
 
     @Specialization
     @TruffleBoundary
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 b3176f58aedcfdbd7c2642fdf321f3db032c085b..ea10c5aea50987a528ff6974e51dbc6aa87ab0f5 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
@@ -51,7 +51,7 @@ import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
  * Note: remove is invoked from builtin wrappers 'rm' and 'remove' that are identical.
  */
 @RBuiltin(name = "remove", visibility = OFF, kind = INTERNAL, parameterNames = {"list", "envir", "inherits"}, behavior = COMPLEX)
-public abstract class Rm extends RBuiltinNode {
+public abstract class Rm extends RBuiltinNode.Arg3 {
 
     private final BranchProfile invalidateProfile = BranchProfile.create();
 
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 13230809bec5a91311616381d6ef0776ef5aebfa..0b5877e50cca45d3da955ba762198481a9f58718 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
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.ops.UnaryArithmeticFactory;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "round", kind = PRIMITIVE, parameterNames = {"x", "digits"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-public abstract class Round extends RBuiltinNode {
+public abstract class Round extends RBuiltinNode.Arg2 {
 
     public static final UnaryArithmeticFactory ROUND = RoundArithmetic::new;
 
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 e7ac9923d1496b1a90f5323d998ba48536123031..e3c1c874699f60eb4b307736332953ab9fe3acbb 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
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 @RBuiltin(name = "row", kind = INTERNAL, parameterNames = {"dims"}, behavior = PURE)
-public abstract class Row extends RBuiltinNode {
+public abstract class Row extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Row.class);
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 c8b0232b061600362cb111ea0ba85db65a1cd20f..2a1ebf4a7bb389f9d2ee2a4815503fbc8a4e44fe 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public class RowsumFunctions {
 
     @RBuiltin(name = "rowsum_matrix", kind = INTERNAL, parameterNames = {"x", "g", "uniqueg", "snarm", "rn"}, behavior = PURE)
-    public abstract static class Rowsum extends RBuiltinNode {
+    public abstract static class Rowsum extends RBuiltinNode.Arg5 {
 
         private final ConditionProfile typeProfile = ConditionProfile.createBinaryProfile();
         private final NACheck na = NACheck.create();
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 867f378c97ade491bc1c031379057a49d161e4a6..8c2dfd931fb2250ce24f3773507661916e4729e0 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
@@ -52,41 +52,44 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
-public abstract class S3DispatchFunctions extends RBuiltinNode {
+public abstract class S3DispatchFunctions {
 
-    @Child private S3FunctionLookupNode methodLookup;
-    @Child private CallMatcherNode callMatcher;
+    private static final class Helper extends RBaseNode {
+        @Child private S3FunctionLookupNode methodLookup;
+        @Child private CallMatcherNode callMatcher;
 
-    private final ConditionProfile callerFrameSlowPath = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile topLevelFrameProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile callerFrameSlowPath = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile topLevelFrameProfile = ConditionProfile.createBinaryProfile();
 
-    protected S3DispatchFunctions(boolean nextMethod) {
-        methodLookup = S3FunctionLookupNode.create(true, nextMethod);
-        callMatcher = CallMatcherNode.create(false);
-    }
+        protected Helper(boolean nextMethod) {
+            methodLookup = S3FunctionLookupNode.create(true, nextMethod);
+            callMatcher = CallMatcherNode.create(false);
+        }
 
-    protected MaterializedFrame getCallerFrame(VirtualFrame frame) {
-        MaterializedFrame funFrame = RArguments.getCallerFrame(frame);
-        if (callerFrameSlowPath.profile(funFrame == null)) {
-            funFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE).materialize();
-            RError.performanceWarning("slow caller frame access in UseMethod dispatch");
+        protected MaterializedFrame getCallerFrame(VirtualFrame frame) {
+            MaterializedFrame funFrame = RArguments.getCallerFrame(frame);
+            if (callerFrameSlowPath.profile(funFrame == null)) {
+                funFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE).materialize();
+                RError.performanceWarning("slow caller frame access in UseMethod dispatch");
+            }
+            // S3 method can be dispatched from top-level where there is no caller frame
+            return topLevelFrameProfile.profile(funFrame == null) ? frame.materialize() : funFrame;
         }
-        // S3 method can be dispatched from top-level where there is no caller frame
-        return topLevelFrameProfile.profile(funFrame == null) ? frame.materialize() : funFrame;
-    }
 
-    protected Object dispatch(VirtualFrame frame, String generic, RStringVector type, String group, MaterializedFrame callerFrame, MaterializedFrame genericDefFrame,
-                    ArgumentsSignature suppliedSignature, Object[] suppliedArguments) {
-        Result lookupResult = methodLookup.execute(frame, generic, type, group, callerFrame, genericDefFrame);
+        protected Object dispatch(VirtualFrame frame, String generic, RStringVector type, String group, MaterializedFrame callerFrame, MaterializedFrame genericDefFrame,
+                        ArgumentsSignature suppliedSignature, Object[] suppliedArguments) {
+            Result lookupResult = methodLookup.execute(frame, generic, type, group, callerFrame, genericDefFrame);
 
-        S3Args s3Args = new S3Args(lookupResult.generic, lookupResult.clazz, lookupResult.targetFunctionName, callerFrame, genericDefFrame, group);
-        Object result = callMatcher.execute(frame, suppliedSignature, suppliedArguments, lookupResult.function, lookupResult.targetFunctionName, s3Args);
-        return result;
+            S3Args s3Args = new S3Args(lookupResult.generic, lookupResult.clazz, lookupResult.targetFunctionName, callerFrame, genericDefFrame, group);
+            Object result = callMatcher.execute(frame, suppliedSignature, suppliedArguments, lookupResult.function, lookupResult.targetFunctionName, s3Args);
+            return result;
+        }
     }
 
     @RBuiltin(name = "UseMethod", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"generic", "object"}, behavior = COMPLEX)
-    public abstract static class UseMethod extends S3DispatchFunctions {
+    public abstract static class UseMethod extends RBuiltinNode.Arg2 {
 
         /*
          * TODO: If more than two parameters are passed to UseMethod the extra parameters are
@@ -95,6 +98,7 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
 
         @Child private ClassHierarchyNode classHierarchyNode = ClassHierarchyNodeGen.create(true, true);
         @Child private PromiseCheckHelperNode promiseCheckHelper;
+        @Child private Helper helper = new Helper(false);
 
         private final BranchProfile firstArgMissing = BranchProfile.create();
         private final ConditionProfile argMissingProfile = ConditionProfile.createBinaryProfile();
@@ -104,10 +108,6 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
             Casts.noCasts(UseMethod.class);
         }
 
-        protected UseMethod() {
-            super(false);
-        }
-
         @Specialization
         protected Object execute(VirtualFrame frame, String generic, Object arg) {
             Object dispatchedObject;
@@ -119,12 +119,12 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
             }
 
             RStringVector type = dispatchedObject == null ? RDataFactory.createEmptyStringVector() : classHierarchyNode.execute(dispatchedObject);
-            MaterializedFrame callerFrame = getCallerFrame(frame);
+            MaterializedFrame callerFrame = helper.getCallerFrame(frame);
             MaterializedFrame genericDefFrame = RArguments.getEnclosingFrame(frame);
 
             ArgumentsSignature suppliedSignature = RArguments.getSuppliedSignature(frame);
             Object[] suppliedArguments = RArguments.getArguments(frame);
-            Object result = dispatch(frame, generic, type, null, callerFrame, genericDefFrame, suppliedSignature, suppliedArguments);
+            Object result = helper.dispatch(frame, generic, type, null, callerFrame, genericDefFrame, suppliedSignature, suppliedArguments);
             throw new ReturnException(result, RArguments.getCall(frame));
         }
 
@@ -173,7 +173,7 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
     }
 
     @RBuiltin(name = "NextMethod", visibility = CUSTOM, kind = SUBSTITUTE, parameterNames = {"generic", "object", "..."}, behavior = COMPLEX)
-    public abstract static class NextMethod extends S3DispatchFunctions {
+    public abstract static class NextMethod extends RBuiltinNode.Arg3 {
 
         @Child private LocalReadVariableNode rvnGroup = LocalReadVariableNode.create(RRuntime.R_DOT_GROUP, false);
         @Child private LocalReadVariableNode rvnClass = LocalReadVariableNode.create(RRuntime.R_DOT_CLASS, false);
@@ -186,6 +186,7 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
 
         @Child private PromiseHelperNode promiseHelper;
         @Child private ClassHierarchyNode hierarchy;
+        @Child private Helper helper = new Helper(true);
 
         private final ConditionProfile emptyArgsProfile = ConditionProfile.createBinaryProfile();
         private final ConditionProfile genericCallFrameNullProfile = ConditionProfile.createBinaryProfile();
@@ -199,10 +200,6 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
             Casts.noCasts(NextMethod.class);
         }
 
-        protected NextMethod() {
-            super(true);
-        }
-
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RNull.instance, RNull.instance, RArgsValuesAndNames.EMPTY};
@@ -252,7 +249,7 @@ public abstract class S3DispatchFunctions extends RBuiltinNode {
                 suppliedArguments = combinedResult.getArguments();
                 finalSignature = combinedResult.getSignature();
             }
-            return dispatch(frame, generic, readType(frame), group, genericCallFrame, genericDefFrame, finalSignature, suppliedArguments);
+            return helper.dispatch(frame, generic, readType(frame), group, genericCallFrame, genericDefFrame, finalSignature, suppliedArguments);
         }
 
         private MaterializedFrame getDefFrame(VirtualFrame frame) {
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 fd7cbae8c14bae0230dfbe26e30d0b8b90ed0476..1e79a7792b9ff3253a0e59fce872de77ba2dbc3a 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.rng.RRNG;
 
 @RBuiltin(name = "sample", kind = INTERNAL, parameterNames = {"x", "size", "replace", "prob"}, behavior = MODIFIES_STATE)
-public abstract class Sample extends RBuiltinNode {
+public abstract class Sample extends RBuiltinNode.Arg4 {
     private final ConditionProfile sampleSizeProfile = ConditionProfile.createBinaryProfile();
 
     static {
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 e5ce462981f382657ae397313a30e0e8ca5505d0..8adbb2699ea6c5c07ab9dd6539d04ffc8455e162 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.rng.RRNG;
  * Sample2 is more efficient special case implementation of {@link Sample}.
  */
 @RBuiltin(name = "sample2", kind = INTERNAL, parameterNames = {"x", "size"}, behavior = MODIFIES_STATE)
-public abstract class Sample2 extends RBuiltinNode {
+public abstract class Sample2 extends RBuiltinNode.Arg2 {
     private static final double U = 33554432.0;
     static final double MAX_INT = Integer.MAX_VALUE;
 
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 85512d6eba7d0f79d225b01b323afa036ba5ccb8..62c1180a129d6d3328e09ef5f968adc5082e56ac 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
@@ -58,7 +58,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "scan", kind = INTERNAL, parameterNames = {"file", "what", "nmax", "sep", "dec", "quote", "skip", "nlines", "na.strings", "flush", "fill", "strip.white", "quiet", "blank.lines.skip",
                 "multi.line", "comment.char", "allowEscapes", "encoding", "skipNull"}, behavior = IO)
-public abstract class Scan extends RBuiltinNode {
+public abstract class Scan extends RBuiltinNode.Arg19 {
 
     private static final int SCAN_BLOCKSIZE = 1000;
     private static final int NO_COMCHAR = 100000; /* won't occur even in Unicode */
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 25e8d6eaeb611ef3abc24680873cde862e2e4cf3..2207d2344401236c3ac62f2e5d60051df4e46978 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
@@ -324,7 +324,7 @@ public final class SeqFunctions {
 
     @TypeSystemReference(RTypes.class)
     @RBuiltin(name = "seq_along", kind = PRIMITIVE, parameterNames = {"along.with"}, behavior = PURE)
-    public abstract static class SeqAlong extends RBuiltinNode {
+    public abstract static class SeqAlong extends RBuiltinNode.Arg1 {
         @Child private ClassHierarchyNode classHierarchyNode = ClassHierarchyNode.create();
 
         static {
@@ -366,7 +366,7 @@ public final class SeqFunctions {
 
     @TypeSystemReference(RTypes.class)
     @RBuiltin(name = "seq_len", kind = PRIMITIVE, parameterNames = {"length.out"}, behavior = PURE)
-    public abstract static class SeqLen extends RBuiltinNode {
+    public abstract static class SeqLen extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(SeqLen.class);
@@ -403,12 +403,11 @@ public final class SeqFunctions {
      *
      * N.B. javac gives error "cannot find symbol" on plain "@RBuiltin".
      */
-    @TypeSystemReference(RTypes.class)
+    @SuppressWarnings("unused")
     @ImportStatic({AsRealNodeGen.class, SeqFunctions.class})
     @com.oracle.truffle.r.runtime.builtins.RBuiltin(name = "seq.int", kind = PRIMITIVE, parameterNames = {"from", "to", "by", "length.out", "along.with",
                     "..."}, dispatch = INTERNAL_GENERIC, genericName = "seq", behavior = PURE)
-    @SuppressWarnings("unused")
-    public abstract static class SeqInt extends RBuiltinNode {
+    public abstract static class SeqInt extends RBuiltinNode.Arg5 {
         private final BranchProfile error = BranchProfile.create();
         private final boolean seqFastPath;
 
@@ -426,7 +425,8 @@ public final class SeqFunctions {
             casts.arg("length.out").allowMissing().mapIf(nullValue(), missingConstant());
         }
 
-        protected abstract Object execute(VirtualFrame frame, Object start, Object to, Object by, Object lengthOut, Object alongWith);
+        @Override
+        public abstract Object execute(VirtualFrame frame, Object start, Object to, Object by, Object lengthOut, Object alongWith);
 
         protected SeqInt(boolean seqFastPath) {
             this.seqFastPath = seqFastPath;
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 7ca7bccf0042986e7ca72bf60ec9794c0493d862..8d1d96657307c3c77269954db15558cf88c23a05 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,6 +35,7 @@ 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.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -46,52 +47,51 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 public class SerializeFunctions {
 
-    public abstract static class Adapter extends RBuiltinNode {
-        @TruffleBoundary
-        protected Object doUnserializeFromConnBase(int connIndex, @SuppressWarnings("unused") REnvironment refhook) {
-            try (RConnection openConn = RConnection.fromIndex(connIndex).forceOpen("rb")) {
-                if (!openConn.canRead()) {
-                    throw error(RError.Message.CONNECTION_NOT_OPEN_READ);
-                }
-                return RSerialize.unserialize(openConn);
-            } catch (IOException ex) {
-                throw error(RError.Message.GENERIC, ex.getMessage());
+    @TruffleBoundary
+    protected static Object doUnserializeFromConnBase(RBaseNode node, int connIndex, @SuppressWarnings("unused") REnvironment refhook) {
+        try (RConnection openConn = RConnection.fromIndex(connIndex).forceOpen("rb")) {
+            if (!openConn.canRead()) {
+                throw node.error(RError.Message.CONNECTION_NOT_OPEN_READ);
             }
+            return RSerialize.unserialize(openConn);
+        } catch (IOException ex) {
+            throw node.error(RError.Message.GENERIC, ex.getMessage());
         }
+    }
+
+    @TruffleBoundary
+    protected static Object doUnserializeFromRaw(RAbstractRawVector data, @SuppressWarnings("unused") REnvironment refhook) {
+        return RSerialize.unserialize(data);
+    }
 
-        @TruffleBoundary
-        protected Object doUnserializeFromRaw(RAbstractRawVector data, @SuppressWarnings("unused") REnvironment refhook) {
-            return RSerialize.unserialize(data);
-        }
-
-        @TruffleBoundary
-        protected Object doSerializeToConnBase(Object object, int connIndex, int type, @SuppressWarnings("unused") byte xdrLogical, @SuppressWarnings("unused") RNull version,
-                        @SuppressWarnings("unused") RNull refhook) {
-            // xdr is only relevant if ascii is false
-            try (RConnection openConn = RConnection.fromIndex(connIndex).forceOpen(type != RSerialize.XDR ? "wt" : "wb")) {
-                if (!openConn.canWrite()) {
-                    throw error(RError.Message.CONNECTION_NOT_OPEN_WRITE);
-                }
-                if (type == RSerialize.XDR && openConn.isTextMode()) {
-                    throw error(RError.Message.BINARY_CONNECTION_REQUIRED);
-                }
-                RSerialize.serialize(openConn, object, type, RSerialize.DEFAULT_VERSION, null);
-                return RNull.instance;
-            } catch (IOException ex) {
-                throw error(RError.Message.GENERIC, ex.getMessage());
+    @TruffleBoundary
+    protected static Object doSerializeToConnBase(RBaseNode node, Object object, int connIndex, int type, @SuppressWarnings("unused") byte xdrLogical, @SuppressWarnings("unused") RNull version,
+                    @SuppressWarnings("unused") RNull refhook) {
+        // xdr is only relevant if ascii is false
+        try (RConnection openConn = RConnection.fromIndex(connIndex).forceOpen(type != RSerialize.XDR ? "wt" : "wb")) {
+            if (!openConn.canWrite()) {
+                throw node.error(RError.Message.CONNECTION_NOT_OPEN_WRITE);
             }
+            if (type == RSerialize.XDR && openConn.isTextMode()) {
+                throw node.error(RError.Message.BINARY_CONNECTION_REQUIRED);
+            }
+            RSerialize.serialize(openConn, object, type, RSerialize.DEFAULT_VERSION, null);
+            return RNull.instance;
+        } catch (IOException ex) {
+            throw node.error(RError.Message.GENERIC, ex.getMessage());
         }
+    }
 
-        protected static void connection(Casts casts) {
-            casts.arg("con").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 {
+    public abstract static class UnserializeFromConn extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(UnserializeFromConn.class);
@@ -100,18 +100,18 @@ public class SerializeFunctions {
 
         @Specialization
         protected Object doUnserializeFromConn(int conn, @SuppressWarnings("unused") RNull refhook) {
-            return doUnserializeFromConnBase(conn, null);
+            return doUnserializeFromConnBase(this, conn, null);
         }
 
         @Specialization
         protected Object doUnserializeFromConn(int conn, @SuppressWarnings("unused") REnvironment refhook) {
             // TODO figure out what this really means?
-            return doUnserializeFromConnBase(conn, null);
+            return doUnserializeFromConnBase(this, conn, null);
         }
     }
 
     @RBuiltin(name = "serializeToConn", visibility = OFF, kind = INTERNAL, parameterNames = {"object", "con", "ascii", "version", "refhook"}, behavior = IO)
-    public abstract static class SerializeToConn extends Adapter {
+    public abstract static class SerializeToConn extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(SerializeToConn.class);
@@ -132,7 +132,7 @@ public class SerializeFunctions {
             } else {
                 type = RSerialize.XDR;
             }
-            return doSerializeToConnBase(object, conn, type, RRuntime.LOGICAL_NA, version, refhook);
+            return doSerializeToConnBase(this, object, conn, type, RRuntime.LOGICAL_NA, version, refhook);
         }
 
         @SuppressWarnings("unused")
@@ -144,7 +144,7 @@ public class SerializeFunctions {
     }
 
     @RBuiltin(name = "unserialize", kind = INTERNAL, parameterNames = {"con", "refhook"}, behavior = IO)
-    public abstract static class Unserialize extends Adapter {
+    public abstract static class Unserialize extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(Unserialize.class);
@@ -154,7 +154,7 @@ public class SerializeFunctions {
 
         @Specialization
         protected Object unSerialize(int conn, @SuppressWarnings("unused") RNull refhook) {
-            return doUnserializeFromConnBase(conn, null);
+            return doUnserializeFromConnBase(this, conn, null);
         }
 
         @Specialization
@@ -164,7 +164,7 @@ public class SerializeFunctions {
     }
 
     @RBuiltin(name = "serialize", kind = INTERNAL, parameterNames = {"object", "con", "type", "version", "refhook"}, behavior = IO)
-    public abstract static class Serialize extends Adapter {
+    public abstract static class Serialize extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(Serialize.class);
@@ -174,7 +174,7 @@ public class SerializeFunctions {
 
         @Specialization
         protected Object serialize(Object object, int conn, int type, RNull version, RNull refhook) {
-            return doSerializeToConnBase(object, conn, type, RRuntime.LOGICAL_NA, version, refhook);
+            return doSerializeToConnBase(this, object, conn, type, RRuntime.LOGICAL_NA, version, refhook);
         }
 
         @SuppressWarnings("unused")
@@ -186,7 +186,7 @@ public class SerializeFunctions {
     }
 
     @RBuiltin(name = "serializeb", kind = INTERNAL, parameterNames = {"object", "con", "xdr", "version", "refhook"}, behavior = IO)
-    public abstract static class SerializeB extends Adapter {
+    public abstract static class SerializeB extends RBuiltinNode.Arg5 {
 
         static {
             Casts casts = new Casts(SerializeB.class);
@@ -199,7 +199,7 @@ public class SerializeFunctions {
             if (!RRuntime.fromLogical(xdrLogical)) {
                 throw RError.nyi(this, "xdr==FALSE");
             }
-            return doSerializeToConnBase(object, conn, RRuntime.LOGICAL_FALSE, xdrLogical, version, refhook);
+            return doSerializeToConnBase(this, object, conn, RRuntime.LOGICAL_FALSE, xdrLogical, version, refhook);
         }
     }
 }
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 c590cebea82a1381134463ff9b5ff6a0c378471b..bc74b10deb46f6f2f428c9b172a82f136a539676 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RSequence;
 
 @RBuiltin(name = "setS4Object", kind = INTERNAL, parameterNames = {"object", "flag", "complete"}, behavior = PURE)
-public abstract class SetS4Object extends RBuiltinNode {
+public abstract class SetS4Object extends RBuiltinNode.Arg3 {
 
     @Child private AsS4 asS4 = AsS4NodeGen.create();
 
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 1b89fd845d9dbf51868d1edbe4d16746ce729a44..175bf4347b1f4dde19997b0aeb528b6c4c7c4e21 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
@@ -33,7 +33,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 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 {
+public abstract class SetTimeLimit extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(SetTimeLimit.class);
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 42c91558b5ccc610d069398be69a899c4e35affb..92ca9352eafb946d049bb19e5cbcd3defa9289bd 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 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 {
+public abstract class Setwd extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Setwd.class);
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 d06c25acbdc4697e09cf1f893942ebdfb826e33d..9d9e87d1c0e3cc7a032311959d65dec6d46c54e4 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "shortRowNames", kind = INTERNAL, parameterNames = {"x", "type"}, behavior = PURE)
-public abstract class ShortRowNames extends RBuiltinNode {
+public abstract class ShortRowNames extends RBuiltinNode.Arg2 {
 
     private final BranchProfile naValueMet = BranchProfile.create();
     private final ValueProfile operandTypeProfile = ValueProfile.createClassProfile();
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 5c3afc71a88a397a4839c202e2362c4c5ed9fcb3..1ef56ebc6b17357b39cb72c0b879006c7038d680 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
@@ -55,7 +55,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "signif", kind = PRIMITIVE, parameterNames = {"x", "digits"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-public abstract class Signif extends RBuiltinNode {
+public abstract class Signif extends RBuiltinNode.Arg2 {
 
     @Override
     public Object[] getDefaultParameterValues() {
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 c187408a6a8b7a3d35ed254774b9d7c4ce652d32..313a824464980e11457c7a1f626586f9949367dd 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
@@ -41,7 +41,7 @@ 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 {
+    public abstract static class Sink extends RBuiltinNode.Arg4 {
 
         static {
             Casts casts = new Casts(Sink.class);
@@ -77,7 +77,7 @@ public class SinkFunctions {
     }
 
     @RBuiltin(name = "sink.number", kind = INTERNAL, parameterNames = {"type"}, behavior = IO)
-    public abstract static class SinkNumber extends RBuiltinNode {
+    public abstract static class SinkNumber extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(SinkNumber.class);
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 f352c35e802a251e015d1d5de16b0b79921f32d5..98c7e6420098a0b05fac67463bd3adf6275a0cf2 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
@@ -34,7 +34,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 
 @RBuiltin(name = "@", kind = PRIMITIVE, parameterNames = {"", ""}, nonEvalArgs = 1, behavior = COMPLEX)
-public abstract class Slot extends RBuiltinNode {
+public abstract class Slot extends RBuiltinNode.Arg2 {
 
     @Child private UpdateShareableChildValueNode sharedAttrUpdate = UpdateShareableChildValueNode.create();
     @Child private AccessSlotNode accessSlotNode = AccessSlotNodeGen.create(true);
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 1dc73f73451fb89c6cceea305d316d66ada59530..1cbef88f119a988783ab30f87c7841653f9714b4 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
@@ -23,6 +23,7 @@
 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.constant;
 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.integerValue;
@@ -41,7 +42,7 @@ 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.Predef;
+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;
@@ -66,88 +67,86 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
  */
 public class SortFunctions {
 
-    private abstract static class Adapter extends RBuiltinNode {
-        protected static void addCastForX(Casts casts) {
-            casts.arg("x").allowNull().mustBe(rawValue().not(), RAW_SORT).mustBe(instanceOf(RAbstractListVector.class).not(), ONLY_ATOMIC_CAN_BE_SORTED).mustBe(
-                            abstractVectorValue(), ONLY_ATOMIC_CAN_BE_SORTED);
-        }
+    protected static void addCastForX(Casts casts) {
+        casts.arg("x").allowNull().mustBe(rawValue().not(), RAW_SORT).mustBe(instanceOf(RAbstractListVector.class).not(), ONLY_ATOMIC_CAN_BE_SORTED).mustBe(
+                        abstractVectorValue(), ONLY_ATOMIC_CAN_BE_SORTED);
+    }
 
-        protected static void addCastForDecreasing(Casts casts) {
-            casts.arg("decreasing").defaultError(INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().map(toBoolean());
-        }
+    protected static void addCastForDecreasing(Casts casts) {
+        casts.arg("decreasing").defaultError(INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().map(toBoolean());
+    }
 
-        @TruffleBoundary
-        private static double[] sort(double[] data, boolean decreasing) {
-            // no reverse comparator for primitives
-            Arrays.parallelSort(data);
-            if (decreasing) {
-                int len = data.length;
-                for (int i = len / 2 - 1; i >= 0; i--) {
-                    double temp = data[i];
-                    data[i] = data[len - i - 1];
-                    data[len - i - 1] = temp;
-                }
+    @TruffleBoundary
+    private static double[] sort(double[] data, boolean decreasing) {
+        // no reverse comparator for primitives
+        Arrays.parallelSort(data);
+        if (decreasing) {
+            int len = data.length;
+            for (int i = len / 2 - 1; i >= 0; i--) {
+                double temp = data[i];
+                data[i] = data[len - i - 1];
+                data[len - i - 1] = temp;
             }
-            return data;
         }
+        return data;
+    }
 
-        @TruffleBoundary
-        private static int[] sort(int[] data, boolean decreasing) {
-            Arrays.parallelSort(data);
-            if (decreasing) {
-                int len = data.length;
-                for (int i = len / 2 - 1; i >= 0; i--) {
-                    int temp = data[i];
-                    data[i] = data[len - i - 1];
-                    data[len - i - 1] = temp;
-                }
+    @TruffleBoundary
+    private static int[] sort(int[] data, boolean decreasing) {
+        Arrays.parallelSort(data);
+        if (decreasing) {
+            int len = data.length;
+            for (int i = len / 2 - 1; i >= 0; i--) {
+                int temp = data[i];
+                data[i] = data[len - i - 1];
+                data[len - i - 1] = temp;
             }
-            return data;
         }
+        return data;
+    }
 
-        @TruffleBoundary
-        private static byte[] sort(byte[] data, boolean decreasing) {
-            Arrays.parallelSort(data);
-            if (decreasing) {
-                int len = data.length;
-                for (int i = len / 2 - 1; i >= 0; i--) {
-                    byte temp = data[i];
-                    data[i] = data[len - i - 1];
-                    data[len - i - 1] = temp;
-                }
+    @TruffleBoundary
+    private static byte[] sort(byte[] data, boolean decreasing) {
+        Arrays.parallelSort(data);
+        if (decreasing) {
+            int len = data.length;
+            for (int i = len / 2 - 1; i >= 0; i--) {
+                byte temp = data[i];
+                data[i] = data[len - i - 1];
+                data[len - i - 1] = temp;
             }
-            return data;
         }
+        return data;
+    }
 
-        @TruffleBoundary
-        private static String[] sort(String[] data, boolean decreasing) {
-            if (decreasing) {
-                Arrays.parallelSort(data, Collections.reverseOrder());
-            } else {
-                Arrays.parallelSort(data);
-            }
-            return data;
+    @TruffleBoundary
+    private static String[] sort(String[] data, boolean decreasing) {
+        if (decreasing) {
+            Arrays.parallelSort(data, Collections.reverseOrder());
+        } else {
+            Arrays.parallelSort(data);
         }
+        return data;
+    }
 
-        protected RDoubleVector jdkSort(RAbstractDoubleVector vec, boolean decreasing) {
-            double[] data = vec.materialize().getDataCopy();
-            return RDataFactory.createDoubleVector(sort(data, decreasing), vec.isComplete());
-        }
+    protected static RDoubleVector jdkSort(RAbstractDoubleVector vec, boolean decreasing) {
+        double[] data = vec.materialize().getDataCopy();
+        return RDataFactory.createDoubleVector(sort(data, decreasing), vec.isComplete());
+    }
 
-        protected RIntVector jdkSort(RAbstractIntVector vec, boolean decreasing) {
-            int[] data = vec.materialize().getDataCopy();
-            return RDataFactory.createIntVector(sort(data, decreasing), vec.isComplete());
-        }
+    protected static RIntVector jdkSort(RAbstractIntVector vec, boolean decreasing) {
+        int[] data = vec.materialize().getDataCopy();
+        return RDataFactory.createIntVector(sort(data, decreasing), vec.isComplete());
+    }
 
-        protected RStringVector jdkSort(RAbstractStringVector vec, boolean decreasing) {
-            String[] data = vec.materialize().getDataCopy();
-            return RDataFactory.createStringVector(sort(data, decreasing), vec.isComplete());
-        }
+    protected static RStringVector jdkSort(RAbstractStringVector vec, boolean decreasing) {
+        String[] data = vec.materialize().getDataCopy();
+        return RDataFactory.createStringVector(sort(data, decreasing), vec.isComplete());
+    }
 
-        protected RLogicalVector jdkSort(RAbstractLogicalVector vec, boolean decreasing) {
-            byte[] data = vec.materialize().getDataCopy();
-            return RDataFactory.createLogicalVector(sort(data, decreasing), vec.isComplete());
-        }
+    protected static RLogicalVector jdkSort(RAbstractLogicalVector vec, boolean decreasing) {
+        byte[] data = vec.materialize().getDataCopy();
+        return RDataFactory.createLogicalVector(sort(data, decreasing), vec.isComplete());
     }
 
     /**
@@ -158,7 +157,7 @@ public class SortFunctions {
      * N.B. The R code strips out {@code NA} and {@code NaN} values before calling the builtin.
      */
     @RBuiltin(name = "sort", kind = INTERNAL, parameterNames = {"x", "decreasing"}, behavior = PURE)
-    public abstract static class Sort extends Adapter {
+    public abstract static class Sort extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(Sort.class);
@@ -187,25 +186,25 @@ public class SortFunctions {
         }
 
         @Specialization
-        protected RLogicalVector sort(RAbstractComplexVector vec, boolean decreasing) {
-            throw RError.error(this, RError.Message.UNIMPLEMENTED_ARG_TYPE, 1); // [TODO] implement
-                                                                                // complex sort
+        protected RLogicalVector sort(@SuppressWarnings("unused") RAbstractComplexVector vec, @SuppressWarnings("unused") boolean decreasing) {
+            // TODO: implement complex sort
+            throw RError.error(this, RError.Message.UNIMPLEMENTED_ARG_TYPE, 1);
         }
 
         @Specialization
-        protected RNull sort(RNull vec, boolean decreasing) {
+        protected RNull sort(@SuppressWarnings("unused") RNull vec, @SuppressWarnings("unused") boolean decreasing) {
             return RNull.instance;
         }
 
     }
 
     @RBuiltin(name = "qsort", kind = INTERNAL, parameterNames = {"x", "decreasing"}, behavior = PURE)
-    public abstract static class QSort extends Adapter {
+    public abstract static class QSort extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(QSort.class);
             casts.arg("x").defaultError(NOT_NUMERIC_VECTOR).mustBe(instanceOf(RAbstractListVector.class).not()).mustBe(integerValue().or(doubleValue()));
-            casts.arg("decreasing").mapIf(numericValue().not(), Predef.constant(RRuntime.LOGICAL_TRUE)).asLogicalVector().findFirst().map(toBoolean());
+            casts.arg("decreasing").mapIf(numericValue().not(), constant(RRuntime.LOGICAL_TRUE)).asLogicalVector().findFirst().map(toBoolean());
         }
 
         @Specialization
@@ -220,7 +219,7 @@ public class SortFunctions {
     }
 
     @RBuiltin(name = "psort", kind = INTERNAL, parameterNames = {"x", "partial"}, behavior = PURE)
-    public abstract static class PartialSort extends Adapter {
+    public abstract static class PartialSort extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(PartialSort.class);
@@ -258,7 +257,7 @@ public class SortFunctions {
         }
 
         @Specialization
-        protected RNull sort(RNull vec, Object partial) {
+        protected RNull sort(@SuppressWarnings("unused") RNull vec, @SuppressWarnings("unused") Object partial) {
             return RNull.instance;
         }
     }
@@ -270,7 +269,7 @@ public class SortFunctions {
      * now we delegate to {@code order} and do not implement the {@code retgrp} argument.
      */
     @RBuiltin(name = "radixsort", kind = INTERNAL, parameterNames = {"na.last", "decreasing", "retgrp", "sortstr", "..."}, behavior = PURE)
-    public abstract static class RadixSort extends Adapter {
+    public abstract static class RadixSort extends RBuiltinNode.Arg5 {
         @Child private Order orderNode = OrderNodeGen.create();
 
         static {
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 b43d2e7fc99f702010a8b8dc62359b7caa97faad..8a5446c3d6af500002450e0b5686860bd2c4f872 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
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
  * identical except for the argument type.
  */
 @RBuiltin(name = "split", kind = INTERNAL, parameterNames = {"x", "f"}, behavior = PURE)
-public abstract class Split extends RBuiltinNode {
+public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Child private RFactorNodes.GetLevels getLevelNode = new RFactorNodes.GetLevels();
 
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 cb0c9bd89acc530b56c727ee76bc43083f05714f..fcadf58d328e1fd882f6721e5453e36135a1b4b0 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
@@ -46,7 +46,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "sprintf", kind = INTERNAL, parameterNames = {"fmt", "..."}, behavior = PURE)
 
-public abstract class Sprintf extends RBuiltinNode {
+public abstract class Sprintf extends RBuiltinNode.Arg2 {
 
     static {
         Casts.noCasts(Sprintf.class);
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 4a6f412f95ba9b99ca503dd86249161dd341448b..b96cfacbd5033c1377a07298fadd25627c150c40 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
@@ -55,7 +55,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 // transcribed from /src/library/methods/src/methods_list_dispatch.c (R_dispatch_generic function)
 
 @RBuiltin(name = "standardGeneric", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"f", "fdef"}, behavior = COMPLEX)
-public abstract class StandardGeneric extends RBuiltinNode {
+public abstract class StandardGeneric extends RBuiltinNode.Arg2 {
 
     // TODO: for now, we always go through generic dispatch
 
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 37fc9f60f76d5ce92d1e74d067e54c4d800b2ca1..a92d62da66437edbd8a72a9e0a1770ab8cd8a179 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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public class StartsEndsWithFunctions {
 
-    private abstract static class Adapter extends RBuiltinNode {
+    private abstract static class Adapter extends RBuiltinNode.Arg2 {
         private final NACheck naCheck = NACheck.create();
         private final ConditionProfile singlePrefixProfile = ConditionProfile.createBinaryProfile();
 
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 efb1ada9f48b86cc105facbdc6b621367404c7c2..6012893ec50ceb2bf6035604ab840452b369dd84 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = "stop", kind = INTERNAL, parameterNames = {"call", "message"}, behavior = COMPLEX)
-public abstract class Stop extends RBuiltinNode {
+public abstract class Stop extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(Stop.class);
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 969121a265772e30eff27884327f1346d5b7f248..46455a6a6021b4da55619c8292f9e0f0ec5d9fc8 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "strrep", kind = INTERNAL, parameterNames = {"x", "times"}, behavior = PURE)
-public abstract class Strrep extends RBuiltinNode {
+public abstract class Strrep extends RBuiltinNode.Arg2 {
     private final NACheck naCheck = NACheck.create();
 
     static {
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 86e2c0b11b9505253434ebbe8d8cf6805ccf9219..57d4d6171b68c21d7dae1079de4df35e69db4542 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
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.data.RIntVector;
 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 {
+public abstract class Strtoi extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(Strtoi.class);
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 b80c706e8901a4349da27689db033b9e594aaba1..473d041dbbc889dac22cd2ee29b27bf7ab72a083 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
@@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 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 {
+public abstract class Strtrim extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(Strtrim.class);
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 936b647364cadced920327f70b489cc2e2a8af65..5f20186adf19dec50fb43938b0e92e0081f7c3f9 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
@@ -48,7 +48,7 @@ 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)
-public abstract class Substitute extends RBuiltinNode {
+public abstract class Substitute extends RBuiltinNode.Arg2 {
 
     @Child private Quote quote;
 
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 a69ab8d0545334ddb537a5fcfd0842bebcf1e60a..f3c3760c13d7ecc8a04fb997746daf8b64f216e8 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "substr", kind = INTERNAL, parameterNames = {"x", "start", "stop"}, behavior = PURE)
-public abstract class Substr extends RBuiltinNode {
+public abstract class Substr extends RBuiltinNode.Arg3 {
     private final NACheck na = NACheck.create();
     private final BranchProfile everSeenIllegalRange = BranchProfile.create();
     private final ConditionProfile naIndexesProfile = ConditionProfile.createBinaryProfile();
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 bcc5478198fd5d5d61eed0cfd56a2d779591d378..aa347076a2f0e0fcf512add9cbaac212438da4a8 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
@@ -50,7 +50,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  * Sum has combine semantics (TBD: exactly?) and uses a reduce operation on the resulting array.
  */
 @RBuiltin(name = "sum", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE)
-public abstract class Sum extends RBuiltinNode {
+public abstract class Sum extends RBuiltinNode.Arg2 {
 
     protected static final boolean FULL_PRECISION = FastROptions.FullPrecisionSum.getBooleanValue();
 
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 af0650a456cdaf41fd43639fe51393c0c618acdb..e403219f5fd7feb30c88c57bb5e020a8fc7e94b8 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
@@ -52,7 +52,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
  *
  */
 @RBuiltin(name = "switch", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"EXPR", "..."}, nonEvalArgs = 1, behavior = COMPLEX)
-public abstract class Switch extends RBuiltinNode {
+public abstract class Switch extends RBuiltinNode.Arg2 {
 
     @Child private PromiseCheckHelperNode promiseHelper = new PromiseCheckHelperNode();
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
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 79b06579bc33ffc8aac58232b24bf22116380229..ea2f8107dc40567fefc4e7bff43368127a0524d7 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
@@ -74,7 +74,7 @@ import com.oracle.truffle.r.runtime.ffi.BaseRFFI.UtsName;
 public class SysFunctions {
 
     @RBuiltin(name = "Sys.getpid", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class SysGetpid extends RBuiltinNode {
+    public abstract static class SysGetpid extends RBuiltinNode.Arg0 {
         @Child private BaseRFFI.GetpidNode getpidNode = BaseRFFI.GetpidNode.create();
 
         @Specialization
@@ -86,7 +86,7 @@ public class SysFunctions {
     }
 
     @RBuiltin(name = "Sys.getenv", kind = INTERNAL, parameterNames = {"x", "unset"}, behavior = READS_STATE)
-    public abstract static class SysGetenv extends RBuiltinNode {
+    public abstract static class SysGetenv extends RBuiltinNode.Arg2 {
         private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile();
 
         static {
@@ -135,33 +135,31 @@ public class SysFunctions {
      * code depends critically in the current implementation which sets/unsets this environment
      * variable around a call to loadNamespace/attachNamespace.
      */
-    protected abstract static class LoadNamespaceAdapter extends RBuiltinNode {
-        private static final String NS_LOAD = "_R_NS_LOAD_";
-        private static final String LOADNAMESPACE = "loadNamespace";
+    private static final String NS_LOAD = "_R_NS_LOAD_";
+    private static final String LOADNAMESPACE = "loadNamespace";
 
-        protected void checkNSLoad(VirtualFrame frame, RAbstractStringVector names, RAbstractStringVector values, boolean setting) {
-            if (names.getLength() == 1 && NS_LOAD.equals(names.getDataAt(0))) {
-                doCheckNSLoad(frame.materialize(), values, setting);
-            }
+    protected static void checkNSLoad(VirtualFrame frame, RAbstractStringVector names, RAbstractStringVector values, boolean setting) {
+        if (names.getLength() == 1 && NS_LOAD.equals(names.getDataAt(0))) {
+            doCheckNSLoad(frame.materialize(), values, setting);
         }
+    }
 
-        @TruffleBoundary
-        private static void doCheckNSLoad(MaterializedFrame frame, RAbstractStringVector values, boolean setting) {
-            Frame caller = Utils.getCallerFrame(frame, FrameAccess.READ_ONLY);
-            RFunction func = RArguments.getFunction(caller);
-            if (func.toString().equals(LOADNAMESPACE)) {
-                if (setting) {
-                    RContext.getInstance().setNamespaceName(values.getDataAt(0));
-                } else {
-                    // Now we can run the overrides
-                    RBuiltinPackages.loadDefaultPackageOverrides(RContext.getInstance().getNamespaceName());
-                }
+    @TruffleBoundary
+    private static void doCheckNSLoad(MaterializedFrame frame, RAbstractStringVector values, boolean setting) {
+        Frame caller = Utils.getCallerFrame(frame, FrameAccess.READ_ONLY);
+        RFunction func = RArguments.getFunction(caller);
+        if (func.toString().equals(LOADNAMESPACE)) {
+            if (setting) {
+                RContext.getInstance().setNamespaceName(values.getDataAt(0));
+            } else {
+                // Now we can run the overrides
+                RBuiltinPackages.loadDefaultPackageOverrides(RContext.getInstance().getNamespaceName());
             }
         }
     }
 
     @RBuiltin(name = "Sys.setenv", visibility = OFF, kind = INTERNAL, parameterNames = {"nm", "values"}, behavior = MODIFIES_STATE)
-    public abstract static class SysSetEnv extends LoadNamespaceAdapter {
+    public abstract static class SysSetEnv extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(SysSetEnv.class);
@@ -191,7 +189,7 @@ public class SysFunctions {
     }
 
     @RBuiltin(name = "Sys.unsetenv", visibility = OFF, kind = INTERNAL, parameterNames = {"x"}, behavior = READS_STATE)
-    public abstract static class SysUnSetEnv extends LoadNamespaceAdapter {
+    public abstract static class SysUnSetEnv extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(SysUnSetEnv.class);
@@ -217,7 +215,7 @@ public class SysFunctions {
     }
 
     @RBuiltin(name = "Sys.sleep", visibility = OFF, kind = INTERNAL, parameterNames = {"time"}, behavior = COMPLEX)
-    public abstract static class SysSleep extends RBuiltinNode {
+    public abstract static class SysSleep extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(SysSleep.class);
@@ -248,7 +246,7 @@ public class SysFunctions {
      * TODO: Handle ~ expansion which is not handled by POSIX.
      */
     @RBuiltin(name = "Sys.readlink", kind = INTERNAL, parameterNames = {"paths"}, behavior = IO)
-    public abstract static class SysReadlink extends RBuiltinNode {
+    public abstract static class SysReadlink extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(SysReadlink.class);
@@ -291,7 +289,7 @@ 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 {
+    public abstract static class SysChmod extends RBuiltinNode.Arg3 {
 
         static {
             Casts casts = new Casts(SysChmod.class);
@@ -319,7 +317,7 @@ public class SysFunctions {
 
     // TODO implement
     @RBuiltin(name = "Sys.umask", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"octmode"}, behavior = COMPLEX)
-    public abstract static class SysUmask extends RBuiltinNode {
+    public abstract static class SysUmask extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(SysUmask.class);
@@ -335,7 +333,7 @@ public class SysFunctions {
     }
 
     @RBuiltin(name = "Sys.time", kind = INTERNAL, parameterNames = {}, behavior = IO)
-    public abstract static class SysTime extends RBuiltinNode {
+    public abstract static class SysTime extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected double sysTime() {
@@ -344,7 +342,7 @@ public class SysFunctions {
     }
 
     @RBuiltin(name = "Sys.info", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class SysInfo extends RBuiltinNode {
+    public abstract static class SysInfo extends RBuiltinNode.Arg0 {
         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);
 
@@ -370,7 +368,7 @@ public class SysFunctions {
     }
 
     @RBuiltin(name = "Sys.glob", kind = INTERNAL, parameterNames = {"paths", "dirmask"}, behavior = IO)
-    public abstract static class SysGlob extends RBuiltinNode {
+    public abstract static class SysGlob extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(SysGlob.class);
@@ -399,7 +397,7 @@ public class SysFunctions {
     }
 
     @RBuiltin(name = "setFileTime", kind = INTERNAL, parameterNames = {"path", "time"}, visibility = OFF, behavior = IO)
-    public abstract static class SysSetFileTime extends RBuiltinNode {
+    public abstract static class SysSetFileTime extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(SysSetFileTime.class);
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 7aacea27ab5e0a2fdcb25b2def746a4e0d5977f9..be218cc4bdaa1b350bc24a5531fdcdebde22e102 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
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 @RBuiltin(name = "tabulate", kind = INTERNAL, parameterNames = {"bin", "nbins"}, behavior = PURE)
-public abstract class Tabulate extends RBuiltinNode {
+public abstract class Tabulate extends RBuiltinNode.Arg2 {
 
     private final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile();
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.java
index 022c03adde708e6e668cacd60f45ead87c70599b..d54dbc9845bcac5b867bf9f1294bfb02595c2c7a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TempDir.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,7 +32,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 
 @RBuiltin(name = "tempdir", kind = INTERNAL, parameterNames = {}, behavior = RBehavior.READS_STATE)
-public abstract class TempDir extends RBuiltinNode {
+public abstract class TempDir extends RBuiltinNode.Arg0 {
 
     @Specialization
     protected Object tempdir() {
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 6140aefe45d8bb219a42765d83836bf871448d72..20632a8ef93cd04825ac665510efc6c5b07257bb 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 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 {
+public abstract class TempFile extends RBuiltinNode.Arg3 {
 
     static {
         Casts casts = new Casts(TempFile.class);
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 92d3eb1c98b110834b76f3ca6de0c7dd5ab6df48..7078e5bb37dc2d44cc13d2f0b43f9c34110d81e9 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
@@ -90,7 +90,7 @@ public abstract class ToLowerOrUpper {
     }
 
     @RBuiltin(name = "tolower", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class ToLower extends RBuiltinNode {
+    public abstract static class ToLower extends RBuiltinNode.Arg1 {
 
         @Child private StringMapNode mapNode = StringMapNode.create();
 
@@ -116,7 +116,7 @@ public abstract class ToLowerOrUpper {
     }
 
     @RBuiltin(name = "toupper", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class ToUpper extends RBuiltinNode {
+    public abstract static class ToUpper extends RBuiltinNode.Arg1 {
 
         @Child private StringMapNode mapNode = StringMapNode.create();
 
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 c5d7ba132279dae70d7bade420298eb322448ec8..653e415b77a237fbe5ff6ce295e658208f95aa44 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
@@ -43,6 +43,7 @@ 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.NodeWithArgumentCasts.Casts;
 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;
@@ -65,15 +66,15 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 public class TraceFunctions {
 
-    private abstract static class PrimTraceAdapter extends RBuiltinNode {
-        @Child private GetFunctions.Get getNode;
+    protected static Casts createCasts(Class<? extends RBuiltinNode> extCls) {
+        Casts casts = new Casts(extCls);
+        casts.arg("what").mustBe(instanceOf(RFunction.class).or(stringValue()), Message.ARG_MUST_BE_FUNCTION).mapIf(stringValue(),
+                        chain(asStringVector()).with(findFirst().stringElement()).end());
+        return casts;
+    }
 
-        protected static Casts createCasts(Class<? extends PrimTraceAdapter> extCls) {
-            Casts casts = new Casts(extCls);
-            casts.arg("what").mustBe(instanceOf(RFunction.class).or(stringValue()), Message.ARG_MUST_BE_FUNCTION).mapIf(stringValue(),
-                            chain(asStringVector()).with(findFirst().stringElement()).end());
-            return casts;
-        }
+    private abstract static class PrimTraceAdapter extends RBuiltinNode.Arg1 {
+        @Child private GetFunctions.Get getNode;
 
         protected Object getFunction(VirtualFrame frame, String funcName) {
             if (getNode == null) {
@@ -91,6 +92,8 @@ public class TraceFunctions {
             createCasts(PrimTrace.class);
         }
 
+        public abstract Object execute(VirtualFrame frame, RFunction func);
+
         @Specialization
         protected RNull primTrace(VirtualFrame frame, RAbstractStringVector funcName) {
             return primTrace((RFunction) getFunction(frame, funcName.getDataAt(0)));
@@ -106,6 +109,7 @@ public class TraceFunctions {
             }
             return RNull.instance;
         }
+
     }
 
     @RBuiltin(name = ".primUntrace", visibility = OFF, kind = PRIMITIVE, parameterNames = "what", behavior = COMPLEX)
@@ -115,6 +119,8 @@ public class TraceFunctions {
             createCasts(PrimUnTrace.class);
         }
 
+        public abstract Object execute(VirtualFrame frame, RFunction func);
+
         @Specialization
         protected RNull primUnTrace(VirtualFrame frame, RAbstractStringVector funcName) {
             return primUnTrace((RFunction) getFunction(frame, funcName.getDataAt(0)));
@@ -128,10 +134,11 @@ public class TraceFunctions {
             }
             return RNull.instance;
         }
+
     }
 
     @RBuiltin(name = "traceOnOff", kind = INTERNAL, parameterNames = "state", behavior = COMPLEX)
-    public abstract static class TraceOnOff extends RBuiltinNode {
+    public abstract static class TraceOnOff extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(TraceOnOff.class);
@@ -157,68 +164,66 @@ public class TraceFunctions {
         }
     }
 
-    public abstract static class TracememBase extends RBuiltinNode {
-        static {
-            MemoryCopyTracer.addListener(new TracememBase.TracememListener());
-        }
+    static {
+        MemoryCopyTracer.addListener(new TracememListener());
+    }
 
-        @TruffleBoundary
-        protected static HashSet<Object> getTracedObjects() {
-            return RContext.getInstance().getInstrumentationState().getTracemem().getTracedObjects();
-        }
+    @TruffleBoundary
+    protected static HashSet<Object> getTracedObjects() {
+        return RContext.getInstance().getInstrumentationState().getTracemem().getTracedObjects();
+    }
 
-        @TruffleBoundary
-        protected static String formatHashCode(Object x) {
-            return String.format("<0x%x>", x.hashCode());
-        }
+    @TruffleBoundary
+    protected static String formatHashCode(Object x) {
+        return String.format("<0x%x>", x.hashCode());
+    }
 
-        @TruffleBoundary
-        protected static void startTracing(Object x) {
-            /*
-             * There is no explicit command to enable tracing, it is implicit in the call to
-             * tracemem. However, it can be disabled by tracingState(F), so we can't unilaterally
-             * turn on tracing here.
-             */
-            getTracedObjects().add(x);
-            boolean tracingState = RContext.getInstance().stateInstrumentation.getTracingState();
-            if (tracingState) {
-                MemoryCopyTracer.setTracingState(true);
-            }
+    @TruffleBoundary
+    protected static void startTracing(Object x) {
+        /*
+         * There is no explicit command to enable tracing, it is implicit in the call to tracemem.
+         * However, it can be disabled by tracingState(F), so we can't unilaterally turn on tracing
+         * here.
+         */
+        getTracedObjects().add(x);
+        boolean tracingState = RContext.getInstance().stateInstrumentation.getTracingState();
+        if (tracingState) {
+            MemoryCopyTracer.setTracingState(true);
         }
+    }
 
-        @TruffleBoundary
-        protected static void printToStdout(String msg) {
-            try {
-                StdConnections.getStdout().writeString(msg, true);
-            } catch (IOException ex) {
-                throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, ex.getMessage());
-            }
+    @TruffleBoundary
+    protected static void printToStdout(String msg) {
+        try {
+            StdConnections.getStdout().writeString(msg, true);
+        } catch (IOException ex) {
+            throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, ex.getMessage());
         }
+    }
 
-        @TruffleBoundary
-        protected static String getStackTrace() {
-            final StringBuffer result = new StringBuffer();
-            Truffle.getRuntime().iterateFrames(frame -> {
-                Frame unwrapped = RArguments.unwrap(frame.getFrame(FrameAccess.READ_ONLY));
-                if (RArguments.isRFrame(unwrapped)) {
-                    RCaller call = RArguments.getCall(unwrapped);
-                    if (call != null && call.isValidCaller()) {
-                        result.append(RContext.getRRuntimeASTAccess().getCallerSource(call));
-                        result.append(' ');
-                    }
+    @TruffleBoundary
+    protected static String getStackTrace() {
+        final StringBuffer result = new StringBuffer();
+        Truffle.getRuntime().iterateFrames(frame -> {
+            Frame unwrapped = RArguments.unwrap(frame.getFrame(FrameAccess.READ_ONLY));
+            if (RArguments.isRFrame(unwrapped)) {
+                RCaller call = RArguments.getCall(unwrapped);
+                if (call != null && call.isValidCaller()) {
+                    result.append(RContext.getRRuntimeASTAccess().getCallerSource(call));
+                    result.append(' ');
                 }
-                return null;
-            });
-            return result.toString();
-        }
+            }
+            return null;
+        });
+        return result.toString();
+    }
 
-        private static final class TracememListener implements MemoryCopyTracer.Listener {
-            @TruffleBoundary
-            @Override
-            public void reportCopying(RAbstractVector src, RAbstractVector dest) {
-                if (getTracedObjects().contains(src)) {
-                    printToStdout(String.format("tracemem[0x%x -> 0x%x]: %s", src.hashCode(), dest.hashCode(), getStackTrace()));
-                }
+    private static final class TracememListener implements MemoryCopyTracer.Listener {
+        @TruffleBoundary
+        @Override
+        public void reportCopying(RAbstractVector src, RAbstractVector dest) {
+            if (getTracedObjects().contains(src)) {
+                printToStdout(String.format("tracemem[0x%x -> 0x%x]: %s", src.hashCode(), dest.hashCode(), getStackTrace()));
             }
         }
     }
@@ -229,7 +234,7 @@ public class TraceFunctions {
      * temporary vector wrappers cannot be traced however.
      */
     @RBuiltin(name = "tracemem", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX)
-    public abstract static class Tracemem extends TracememBase {
+    public abstract static class Tracemem extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Tracemem.class);
@@ -249,7 +254,7 @@ public class TraceFunctions {
      * unclear meaning.
      */
     @RBuiltin(name = "retracemem", kind = PRIMITIVE, visibility = CUSTOM, parameterNames = {"x", "previous"}, behavior = COMPLEX)
-    public abstract static class Retracemem extends TracememBase {
+    public abstract static class Retracemem extends RBuiltinNode.Arg2 {
 
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
@@ -291,7 +296,7 @@ public class TraceFunctions {
     }
 
     @RBuiltin(name = "untracemem", kind = PRIMITIVE, visibility = OFF, parameterNames = "x", behavior = COMPLEX)
-    public abstract static class Untracemem extends TracememBase {
+    public abstract static class Untracemem extends RBuiltinNode.Arg1 {
 
         static {
             Casts.noCasts(Untracemem.class);
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 4c75e21ae311d40cd313575f18a934798e8a30a8..898c15fa68cda845ab62826e67bec29d65ff616f 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
@@ -33,7 +33,7 @@ import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "traceback", kind = INTERNAL, parameterNames = {"x"}, behavior = COMPLEX)
-public abstract class Traceback extends RBuiltinNode {
+public abstract class Traceback extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Traceback.class);
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 b75bd4453b87474b2b945052b45d66adc353dad3..db4fa2a7fa41ad40cb1ac8117e331075c79ba5be 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
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @RBuiltin(name = "t.default", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-public abstract class Transpose extends RBuiltinNode {
+public abstract class Transpose extends RBuiltinNode.Arg1 {
 
     private final BranchProfile hasDimNamesProfile = BranchProfile.create();
     private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile();
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 e310690641ee55d8407e4e2cc8e0a98ad867546e..b7b963b1e95d5eaf482c3ecb506a0fa922bb610a 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
@@ -489,7 +489,7 @@ public class TrigExpFunctions {
      * the {@code int} forms to {@code double}.
      */
     @RBuiltin(name = "atan2", kind = INTERNAL, parameterNames = {"y", "x"}, behavior = PURE)
-    public abstract static class Atan2 extends RBuiltinNode {
+    public abstract static class Atan2 extends RBuiltinNode.Arg2 {
 
         private final NACheck yNACheck = NACheck.create();
         private final NACheck xNACheck = NACheck.create();
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 759597b4bcf5180f1955d47e6d3bcb2041856261..6f499ded2d781c258e95c69f223582d9d1d8a810 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.ops.UnaryArithmeticFactory;
 
 @RBuiltin(name = "trunc", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE)
-public abstract class Trunc extends RBuiltinNode {
+public abstract class Trunc extends RBuiltinNode.Arg1 {
 
     private static final UnaryArithmeticFactory TRUNC = TruncArithmetic::new;
 
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 1366ac09fab02734ec974acab00d35836b115e31..4a694e99a52c6bb3f56f1bccfb161c9bbb836dbc 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "typeof", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-public abstract class Typeof extends RBuiltinNode {
+public abstract class Typeof extends RBuiltinNode.Arg1 {
 
     @Child private TypeofNode typeofNode = TypeofNodeGen.create();
 
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 8090c363c0a01db717d346677c7557675af3d403..54fcb5fded17eb70aa2513ba8d2cdca5212772b2 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
@@ -29,7 +29,7 @@ import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "unclass", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-public abstract class UnClass extends RBuiltinNode {
+public abstract class UnClass extends RBuiltinNode.Arg1 {
     private final BranchProfile objectProfile = BranchProfile.create();
     private final BranchProfile shareableProfile = BranchProfile.create();
 
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 8898ee16115b0af79a6551d5cb9347730143e9b2..3ef308f8b141ed5275f074ce3c285149df09ec25 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
@@ -65,7 +65,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 // TODO A more efficient implementation is in order; GNU R uses hash tables so perhaps we should
 // consider using one of the existing libraries that offer hash table implementations for primitive
 // types
-public abstract class Unique extends RBuiltinNode {
+public abstract class Unique extends RBuiltinNode.Arg4 {
 
     private static final long BIG_THRESHOLD = 100;
 
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 5bb9e1786c1c6096e9bb3a7c1a3a9a7544f68349..aeee8fa4fe146c22d85af9c824d5cb1261411b31 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "unlist", kind = INTERNAL, dispatch = RDispatch.INTERNAL_GENERIC, parameterNames = {"x", "recursive", "use.names"}, behavior = PURE)
-public abstract class Unlist extends RBuiltinNode {
+public abstract class Unlist extends RBuiltinNode.Arg3 {
 
     // portions of the algorithm were transcribed from GNU R
 
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 9cbeac74dfe2a31220560e5c1d6fb3d5b19477c3..1487aa333fe33a35c526304cc472372b1006e570 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
@@ -60,7 +60,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "attr<-", kind = PRIMITIVE, parameterNames = {"x", "which", "value"}, behavior = PURE)
-public abstract class UpdateAttr extends RBuiltinNode {
+public abstract class UpdateAttr extends RBuiltinNode.Arg3 {
 
     @Child private UpdateNames updateNames;
     @Child private UpdateDimNames updateDimNames;
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 7bcf40f60ec642e722515825b9a17f198b569aae..70631ae526e5e9eea66795bbc218d85f4feb283d 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
@@ -59,7 +59,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "attributes<-", kind = PRIMITIVE, parameterNames = {"obj", "value"}, behavior = PURE)
-public abstract class UpdateAttributes extends RBuiltinNode {
+public abstract class UpdateAttributes extends RBuiltinNode.Arg2 {
     private final ConditionProfile numAttributesProfile = ConditionProfile.createBinaryProfile();
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
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 b579cd587c27cfa11868438f7060b6013fed2eb0..b32345f7ff7d7d80c006a9356eaf8cdabfcf0617 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
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "class<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, behavior = PURE)
-public abstract class UpdateClass extends RBuiltinNode {
+public abstract class UpdateClass extends RBuiltinNode.Arg2 {
 
     protected static final int CACHE_LIMIT = 2;
 
@@ -203,7 +203,7 @@ public abstract class UpdateClass extends RBuiltinNode {
     private void initCastTypeNode() {
         if (castTypeNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castTypeNode = insert(CastTypeNodeGen.create(null, null));
+            castTypeNode = insert(CastTypeNodeGen.create());
         }
     }
 
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 c59b1b8d5461f74cc574afd2fd27c6d8d6001681..3e3c60210e69161060da326c797a8ad43bdc1274 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
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "dim<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, behavior = PURE)
-public abstract class UpdateDim extends RBuiltinNode {
+public abstract class UpdateDim extends RBuiltinNode.Arg2 {
 
     @Child private ReuseNonSharedNode reuse = ReuseNonSharedNode.create();
 
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 edaea94aabbc6045816056e7fd03476a87e96958..d4b65ff604b3472e0df7cccf0c95e27f3dcd646d 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "dimnames<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class UpdateDimNames extends RBuiltinNode {
+public abstract class UpdateDimNames extends RBuiltinNode.Arg2 {
 
     protected static final String DIMNAMES_ATTR_KEY = RRuntime.DIMNAMES_ATTR_KEY;
 
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 38199269d78caf344dda3e5852a7be155b2c1586..74ada4082119f8221a3d500145dacaeac3972d72 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 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 {
+public abstract class UpdateLength extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(UpdateLength.class);
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 95f8752c97e64fddbde1076f54207d0abcebe9f3..3083e952de63ead07a5a965dc80f1da942dc98d6 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
@@ -28,7 +28,7 @@ import com.oracle.truffle.r.runtime.data.RVector;
 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 {
+public abstract class UpdateLevels extends RBuiltinNode.Arg2 {
 
     static {
         Casts casts = new Casts(UpdateLevels.class);
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 d1ab1ea7f03f4f9fcf7501ab48f4132d5aea35c1..c58e054d13d7f8a640da45c7c0c134c4243714f8 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
@@ -43,7 +43,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "names<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class UpdateNames extends RBuiltinNode {
+public abstract class UpdateNames extends RBuiltinNode.Arg2 {
 
     @Child private CastStringNode castStringNode;
 
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 c0286bb86099fbf9de5d3cb8a24c2b204c219c28..d766b5077cb5f9db803c158a1c91906faba00801 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 // oldClass<- (as opposed to class<-), simply sets the attribute (without handling "implicit" attributes)
 @RBuiltin(name = "oldClass<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, behavior = PURE)
-public abstract class UpdateOldClass extends RBuiltinNode {
+public abstract class UpdateOldClass extends RBuiltinNode.Arg2 {
 
     @Child private CastStringNode castStringNode;
     @Child private SetClassAttributeNode setClassAttributeNode = SetClassAttributeNode.create();
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 684d9ce1e776ce18d07cfc59f4bf3415c079d7b4..560b5fc442c9b3f045b699ee24fb4b268c34dd5e 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
@@ -45,7 +45,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 @RBuiltin(name = "@<-", kind = PRIMITIVE, parameterNames = {"", "", "value"}, nonEvalArgs = 1, behavior = COMPLEX)
-public abstract class UpdateSlot extends RBuiltinNode {
+public abstract class UpdateSlot extends RBuiltinNode.Arg3 {
 
     @Child private UpdateSlotNode updateSlotNode = com.oracle.truffle.r.nodes.access.UpdateSlotNodeGen.create();
 
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 0b45cc5ea9a7713a3813d09137f1a98946b1c94e..c33d4ddb015d8dc5b97ce7ca4815b9811aee0c6f 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
@@ -40,7 +40,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 
 @RBuiltin(name = "storage.mode<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, behavior = PURE)
-public abstract class UpdateStorageMode extends RBuiltinNode {
+public abstract class UpdateStorageMode extends RBuiltinNode.Arg2 {
 
     @Child private TypeFromModeNode typeFromMode = TypeFromModeNodeGen.create();
     @Child private TypeofNode typeof;
@@ -109,7 +109,7 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
     private void initCastTypeNode() {
         if (castTypeNode == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            castTypeNode = insert(CastTypeNodeGen.create(null, null));
+            castTypeNode = insert(CastTypeNodeGen.create());
         }
     }
 
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 21a620a4a83867c83174a8a1faeb7ce862b4d56e..42273c3a7488f8d3df5887bdaf43b6e3636d76f1 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
@@ -45,7 +45,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 @RBuiltin(name = "substr<-", kind = INTERNAL, parameterNames = {"x", "start", "stop", "value"}, behavior = PURE)
-public abstract class UpdateSubstr extends RBuiltinNode {
+public abstract class UpdateSubstr extends RBuiltinNode.Arg4 {
 
     private final NACheck na = NACheck.create();
 
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 52001186a8cf3ede70167e3954274ad7055960cc..ae78e0c4bef95a99d19a192c2c8aa0699f4f383b 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 
 @RBuiltin(name = "utf8ToInt", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-public abstract class Utf8ToInt extends RBuiltinNode {
+public abstract class Utf8ToInt extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(Utf8ToInt.class);
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 48fae23d07e4ee6975dc4a904ece4a894e43c823..f7ca2e99fbd8810ce3974de91d8ced699226c470 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
@@ -79,7 +79,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
  * TODO Set dimnames on result if necessary.
  */
 @RBuiltin(name = "vapply", kind = INTERNAL, parameterNames = {"X", "FUN", "FUN.VALUE", "USE.NAMES"}, splitCaller = true, behavior = COMPLEX)
-public abstract class VApply extends RBuiltinNode {
+public abstract class VApply extends RBuiltinNode.Arg4 {
 
     private final ConditionProfile useNamesProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile dimsProfile = ConditionProfile.createBinaryProfile();
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 001e65fd2cb7529463e639327a47722c211744f6..cb883dd4d41421465ce4b4ed4a00c8d28e6e8e35 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
@@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 
 @RBuiltin(name = "vector", kind = INTERNAL, parameterNames = {"mode", "length"}, behavior = PURE)
-public abstract class Vector extends RBuiltinNode {
+public abstract class Vector extends RBuiltinNode.Arg2 {
 
     private static final String CACHED_MODES_LIMIT = "3";
 
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 164019046ff4edb35b945d0888af84da8adf7d26..fa420e5b0a7d5d79b82ac2805d2fc79eaf49621c 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.RErrorHandling;
 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 {
+public abstract class Warning extends RBuiltinNode.Arg4 {
 
     static {
         Casts casts = new Casts(Warning.class);
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 2345f49d0f4ea1227ff8dfed30cc70eb2252ccef..25a8810a9e29a3e588cd61e397c78e0b43314d93 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
@@ -51,7 +51,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public class WhichFunctions {
 
     @RBuiltin(name = "which", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
-    public abstract static class Which extends RBuiltinNode {
+    public abstract static class Which extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Which.class);
@@ -102,7 +102,7 @@ public class WhichFunctions {
         }
     }
 
-    public abstract static class WhichMinMax extends RBuiltinNode {
+    public abstract static class WhichMinMax extends RBuiltinNode.Arg1 {
 
         private final boolean isMax;
 
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 87accb1d721aab48151ab5f16f58001ca5b097ce..6f2f5ce21b1c2893f0942a4e181f72339a943ff2 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
@@ -67,7 +67,7 @@ final class WithVisibleSpecial extends RNode {
 // 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, nonEvalArgs = {0})
-public abstract class WithVisible extends RBuiltinNode {
+public abstract class WithVisible extends RBuiltinNode.Arg1 {
 
     static final RStringVector LISTNAMES = (RStringVector) RDataFactory.createStringVector(new String[]{"value", "visible"}, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent();
 
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 7d2c7fdfc68f94376451a5b07c2614759a4eb999..abac7f57b85b22c01cf560bddb9d11ab29e4fe4f 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 
 @RBuiltin(name = "xtfrm", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = COMPLEX)
-public abstract class Xtfrm extends RBuiltinNode {
+public abstract class Xtfrm extends RBuiltinNode.Arg1 {
 
     @Child private GetFunctions.Get getNode;
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/AssignFastPath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/AssignFastPath.java
index 377add37242b337a7190bae705e569edbc374d29..ae1586c95a16eb5e756455022ee01516b1fa0638 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/AssignFastPath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/AssignFastPath.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,25 +40,25 @@ public abstract class AssignFastPath extends RFastPathNode {
     @Specialization
     @SuppressWarnings("unused")
     protected Object assign(VirtualFrame frame, RAbstractStringVector x, Object value, RMissing pos, REnvironment envir, byte inherits, Object immediate) {
-        return assign.executeBuiltin(frame, x, value, envir, inherits);
+        return assign.execute(frame, x, value, envir, inherits);
     }
 
     @Specialization
     @SuppressWarnings("unused")
     protected Object assign(VirtualFrame frame, RAbstractStringVector x, Object value, RMissing pos, REnvironment envir, RMissing inherits, Object immediate) {
-        return assign.executeBuiltin(frame, x, value, envir, RRuntime.LOGICAL_FALSE);
+        return assign.execute(frame, x, value, envir, RRuntime.LOGICAL_FALSE);
     }
 
     @Specialization
     @SuppressWarnings("unused")
     protected Object assign(VirtualFrame frame, RAbstractStringVector x, Object value, REnvironment pos, RMissing envir, byte inherits, Object immediate) {
-        return assign.executeBuiltin(frame, x, value, pos, inherits);
+        return assign.execute(frame, x, value, pos, inherits);
     }
 
     @Specialization
     @SuppressWarnings("unused")
     protected Object assign(VirtualFrame frame, RAbstractStringVector x, Object value, REnvironment pos, RMissing envir, RMissing inherits, Object immediate) {
-        return assign.executeBuiltin(frame, x, value, pos, RRuntime.LOGICAL_FALSE);
+        return assign.execute(frame, x, value, pos, RRuntime.LOGICAL_FALSE);
     }
 
     @Fallback
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java
index 056af9a7e51954303bca4e6b688660ec1ddcfa10..0baf7029f035188315c36e2f76e8ffa274bf7551 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java
@@ -26,6 +26,7 @@ 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.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.builtin.base.Matrix;
 import com.oracle.truffle.r.nodes.builtin.base.MatrixNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -55,13 +56,14 @@ public abstract class MatrixFastPath extends RFastPathNode {
                     @Cached("createBinaryProfile()") ConditionProfile rowMissingProfile,
                     @Cached("createBinaryProfile()") ConditionProfile colMissingProfile,
                     @Cached("createBinaryProfile()") ConditionProfile dimMissingProfile,
-                    @Cached("createMatrix()") Matrix matrix) {
+                    @Cached("createMatrix()") Matrix matrix,
+                    @Cached("createClassProfile()") ValueProfile classProfile) {
         boolean rowMissing = rowMissingProfile.profile(nrow == RMissing.instance);
         boolean colMissing = colMissingProfile.profile(ncol == RMissing.instance);
         int row = rowMissing ? 1 : firstRow.executeInt(castRow.execute(nrow));
         int col = colMissing ? 1 : firstCol.executeInt(castCol.execute(ncol));
         Object dim = dimMissingProfile.profile(dimnames == RMissing.instance) ? RNull.instance : dimnames;
-        return matrix.execute(data, row, col, false, dim, rowMissing, colMissing);
+        return matrix.execute(classProfile.profile(data), row, col, false, dim, rowMissing, colMissing);
     }
 
     @Fallback
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 b7bee9a581eb1f2add866a49558752b2e3e1eb72..a498b2d75c9388fa293795c0cf030f46688d9b76 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
@@ -200,10 +200,6 @@ public class CallAndExternalFunctions {
         return list;
     }
 
-    abstract static class CallRFFIAdapter extends LookupAdapter {
-        @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
-    }
-
     /**
      * Handles the generic case, but also many special case functions that are called from the
      * default packages.
@@ -221,7 +217,9 @@ public class CallAndExternalFunctions {
      * could be invoked by a string but experimentally that situation has never been encountered.
      */
     @RBuiltin(name = ".Call", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotCall extends CallRFFIAdapter {
+    public abstract static class DotCall extends LookupAdapter {
+
+        @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
 
         static {
             Casts.noCasts(DotCall.class);
@@ -234,7 +232,7 @@ public class CallAndExternalFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
+        public RExternalBuiltinNode lookupBuiltin(RList symbol) {
             String name = lookupName(symbol);
             if (FastROptions.UseInternalGridGraphics.getBooleanValue() && name != null) {
                 RExternalBuiltinNode gridExternal = FastRGridExternalLookup.lookupDotCall(name);
@@ -656,7 +654,7 @@ public class CallAndExternalFunctions {
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
                         @Cached("symbol") RList cached,
                         @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin,
-                        @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
+                        @Cached("extractSymbolInfo.execute(frame, symbol)") NativeCallInfo nativeCallInfo) {
             return callRFFINode.execute(nativeCallInfo, args.getArguments());
         }
 
@@ -671,7 +669,7 @@ public class CallAndExternalFunctions {
             if (builtin != null) {
                 throw RInternalError.shouldNotReachHere("Cache for .Calls with FastR reimplementation (lookupBuiltin(...) != null) exceeded the limit");
             }
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            NativeCallInfo nativeCallInfo = extractSymbolInfo.execute(frame, symbol);
             return callRFFINode.execute(nativeCallInfo, args.getArguments());
         }
 
@@ -703,7 +701,7 @@ public class CallAndExternalFunctions {
         @SuppressWarnings("unused")
         @Fallback
         protected Object dotCallFallback(Object symbol, Object args, Object packageName) {
-            throw fallback(symbol);
+            throw fallback(this, symbol);
         }
     }
 
@@ -712,7 +710,9 @@ public class CallAndExternalFunctions {
      * {@link DotCall}.
      */
     @RBuiltin(name = ".External", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotExternal extends CallRFFIAdapter {
+    public abstract static class DotExternal extends LookupAdapter {
+
+        @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
 
         static {
             Casts.noCasts(DotExternal.class);
@@ -720,7 +720,7 @@ public class CallAndExternalFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList f) {
+        public RExternalBuiltinNode lookupBuiltin(RList f) {
             String name = lookupName(f);
             if (FastROptions.UseInternalGridGraphics.getBooleanValue()) {
                 RExternalBuiltinNode gridExternal = FastRGridExternalLookup.lookupDotExternal(name);
@@ -780,7 +780,7 @@ public class CallAndExternalFunctions {
         @Specialization(limit = "1", guards = {"cached == symbol"})
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
                         @Cached("symbol") RList cached,
-                        @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
+                        @Cached("extractSymbolInfo.execute(frame, symbol)") NativeCallInfo nativeCallInfo) {
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
             return callRFFINode.execute(nativeCallInfo, new Object[]{list});
         }
@@ -806,12 +806,12 @@ public class CallAndExternalFunctions {
 
         @Fallback
         protected Object fallback(Object f, @SuppressWarnings("unused") Object args, @SuppressWarnings("unused") Object packageName) {
-            throw fallback(f);
+            throw fallback(this, f);
         }
     }
 
     @RBuiltin(name = ".External2", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotExternal2 extends CallRFFIAdapter {
+    public abstract static class DotExternal2 extends LookupAdapter {
         private static final Object CALL = "call";
         private static final Object RHO = "rho";
         /**
@@ -824,6 +824,8 @@ public class CallAndExternalFunctions {
          */
         @CompilationFinal private static Object op = null;
 
+        @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
+
         static {
             Casts.noCasts(DotExternal2.class);
         }
@@ -838,7 +840,7 @@ public class CallAndExternalFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
+        public RExternalBuiltinNode lookupBuiltin(RList symbol) {
             String name = lookupName(symbol);
             if (FastROptions.UseInternalGridGraphics.getBooleanValue()) {
                 RExternalBuiltinNode gridExternal = FastRGridExternalLookup.lookupDotExternal2(name);
@@ -874,7 +876,7 @@ public class CallAndExternalFunctions {
         @Specialization(limit = "1", guards = {"cached == symbol"})
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
                         @Cached("symbol") RList cached,
-                        @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) {
+                        @Cached("extractSymbolInfo.execute(frame, symbol)") NativeCallInfo nativeCallInfo) {
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
             return callRFFINode.execute(nativeCallInfo, new Object[]{CALL, getOp(), list, RHO});
         }
@@ -900,12 +902,14 @@ public class CallAndExternalFunctions {
 
         @Fallback
         protected Object fallback(Object f, @SuppressWarnings("unused") Object args, @SuppressWarnings("unused") Object packageName) {
-            throw fallback(f);
+            throw fallback(this, f);
         }
     }
 
     @RBuiltin(name = ".External.graphics", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotExternalGraphics extends CallRFFIAdapter {
+    public abstract static class DotExternalGraphics extends LookupAdapter {
+
+        @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
 
         static {
             Casts.noCasts(DotExternalGraphics.class);
@@ -913,7 +917,7 @@ public class CallAndExternalFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList f) {
+        public RExternalBuiltinNode lookupBuiltin(RList f) {
             return null;
         }
 
@@ -927,7 +931,7 @@ public class CallAndExternalFunctions {
 
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            NativeCallInfo nativeCallInfo = extractSymbolInfo.execute(frame, symbol);
             Object list = encodeArgumentPairList(args, nativeCallInfo.name);
             return callRFFINode.execute(nativeCallInfo, new Object[]{list});
         }
@@ -952,12 +956,14 @@ public class CallAndExternalFunctions {
 
         @Fallback
         protected Object fallback(Object f, @SuppressWarnings("unused") Object args, @SuppressWarnings("unused") Object packageName) {
-            throw fallback(f);
+            throw fallback(this, f);
         }
     }
 
     @RBuiltin(name = ".Call.graphics", kind = PRIMITIVE, parameterNames = {".NAME", "...", "PACKAGE"}, behavior = COMPLEX)
-    public abstract static class DotCallGraphics extends CallRFFIAdapter {
+    public abstract static class DotCallGraphics extends LookupAdapter {
+
+        @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getRFFI().getCallRFFI().createInvokeCallNode();
 
         static {
             Casts.noCasts(DotCallGraphics.class);
@@ -970,7 +976,7 @@ public class CallAndExternalFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList f) {
+        public RExternalBuiltinNode lookupBuiltin(RList f) {
             switch (lookupName(f)) {
                 default:
                     return null;
@@ -987,7 +993,7 @@ public class CallAndExternalFunctions {
 
         @Specialization
         protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") Object packageName) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            NativeCallInfo nativeCallInfo = extractSymbolInfo.execute(frame, symbol);
             return callRFFINode.execute(nativeCallInfo, args.getArguments());
         }
 
@@ -1011,7 +1017,7 @@ public class CallAndExternalFunctions {
 
         @Fallback
         protected Object dotCallFallback(Object fobj, @SuppressWarnings("unused") Object args, @SuppressWarnings("unused") Object packageName) {
-            throw fallback(fobj);
+            throw fallback(this, fobj);
         }
     }
 }
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 1bdbad5326f2d8ad02b663467df1bc1018410f6d..afdff5f5bcce8fd1e78e753c3aff002b74190c65 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
@@ -22,9 +22,10 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.LookupAdapter.ExtractNativeCallInfoNode;
+import com.oracle.truffle.r.nodes.builtin.base.foreign.LookupAdapterFactory.ExtractNativeCallInfoNodeGen;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -51,7 +52,7 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
  */
 public class FortranAndCFunctions {
 
-    protected abstract static class CRFFIAdapter extends LookupAdapter {
+    protected abstract static class CRFFIAdapter extends RBuiltinNode.Arg6 {
         private static final int SCALAR_DOUBLE = 0;
         private static final int SCALAR_INT = 1;
         private static final int SCALAR_LOGICAL = 2;
@@ -61,6 +62,7 @@ public class FortranAndCFunctions {
         private static final int VECTOR_LOGICAL = 12;
         @SuppressWarnings("unused") private static final int VECTOR_STRING = 12;
 
+        @Child protected ExtractNativeCallInfoNode extractSymbolInfo = ExtractNativeCallInfoNodeGen.create();
         @Child private CRFFI.InvokeCNode invokeCNode = RFFIFactory.getRFFI().getCRFFI().createInvokeCNode();
 
         @Override
@@ -189,7 +191,7 @@ public class FortranAndCFunctions {
      * FastR, otherwise the .Fortran interface uses the machinery that implements the .C interface.
      */
     @RBuiltin(name = ".Fortran", kind = PRIMITIVE, parameterNames = {".NAME", "...", "NAOK", "DUP", "PACKAGE", "ENCODING"}, behavior = COMPLEX)
-    public abstract static class Fortran extends CRFFIAdapter {
+    public abstract static class Fortran extends CRFFIAdapter implements Lookup {
 
         static {
             Casts.noCasts(Fortran.class);
@@ -197,8 +199,8 @@ public class FortranAndCFunctions {
 
         @Override
         @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
-            switch (lookupName(symbol)) {
+        public RExternalBuiltinNode lookupBuiltin(RList symbol) {
+            switch (LookupAdapter.lookupName(symbol)) {
                 case "dqrdc2":
                     return Dqrdc2.create();
                 case "dqrcf":
@@ -219,14 +221,14 @@ public class FortranAndCFunctions {
         @Specialization(guards = "lookupBuiltin(symbol) == null")
         protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, @SuppressWarnings("unused") Object rPackage,
                         @SuppressWarnings("unused") RMissing encoding) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            NativeCallInfo nativeCallInfo = extractSymbolInfo.execute(frame, symbol);
             return dispatch(this, nativeCallInfo, naok, dup, args);
         }
 
         @Specialization
         protected RList c(RAbstractStringVector symbol, RArgsValuesAndNames args, byte naok, byte dup, Object rPackage, @SuppressWarnings("unused") RMissing encoding,
                         @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
-            String libName = checkPackageArg(rPackage);
+            String libName = LookupAdapter.checkPackageArg(rPackage);
             DLL.RegisteredNativeSymbol rns = new DLL.RegisteredNativeSymbol(DLL.NativeSymbolType.Fortran, null, null);
             DLL.SymbolHandle func = findSymbolNode.execute(symbol.getDataAt(0), libName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
@@ -238,7 +240,7 @@ public class FortranAndCFunctions {
         @SuppressWarnings("unused")
         @Fallback
         protected Object fallback(Object symbol, Object args, Object naok, Object dup, Object rPackage, Object encoding) {
-            throw fallback(symbol);
+            throw LookupAdapter.fallback(this, symbol);
         }
     }
 
@@ -249,15 +251,9 @@ public class FortranAndCFunctions {
             Casts.noCasts(DotC.class);
         }
 
-        @Override
-        @TruffleBoundary
-        protected RExternalBuiltinNode lookupBuiltin(RList symbol) {
-            throw RInternalError.shouldNotReachHere();
-        }
-
         @Specialization
         protected RList c(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, byte naok, byte dup, @SuppressWarnings("unused") Object rPackage, @SuppressWarnings("unused") RMissing encoding) {
-            NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol);
+            NativeCallInfo nativeCallInfo = extractSymbolInfo.execute(frame, symbol);
             return dispatch(this, nativeCallInfo, naok, dup, args);
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/LookupAdapter.java
index 31f230f5226efbc9c0c40a1c00d8991adbb69e06..49bcba78821d3eab1788b512a52a45eb64db657e 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
@@ -50,6 +50,11 @@ import com.oracle.truffle.r.runtime.ffi.DLL;
 import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
 import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle;
 import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+
+interface Lookup {
+    RExternalBuiltinNode lookupBuiltin(RList symbol);
+}
 
 /**
  * Locator for "builtin" package function implementations. The "builtin" packages contain many
@@ -58,8 +63,8 @@ import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
  * symbol, created when the package is loaded and stored in the namespace environment of the
  * package, that is a list-valued object. Evidently these "builtins" are somewhat similar to the
  * {@code .Primitive} and {@code .Internal} builtins and, similarly, most of these are
- * re-implemented in Java in FastR. The {@link #lookupBuiltin(RList)} method checks the name in the
- * list object and returns the {@link RExternalBuiltinNode} that implements the function, or
+ * re-implemented in Java in FastR. The {@link Lookup#lookupBuiltin(RList)} method checks the name
+ * in the list object and returns the {@link RExternalBuiltinNode} that implements the function, or
  * {@code null}. A {@code null} result implies that the builtin is not implemented in Java, but
  * called directly via the FFI interface, which is only possible for functions that use the FFI in a
  * way that FastR can handle.
@@ -67,8 +72,8 @@ import com.oracle.truffle.r.runtime.ffi.NativeCallInfo;
  * This class also handles the "lookup" of the {@link NativeCallInfo} data for builtins that are
  * still implemented by native code.
  */
-abstract class LookupAdapter extends RBuiltinNode {
-    @Child private ExtractNativeCallInfoNode extractSymbolInfoNode = ExtractNativeCallInfoNodeGen.create();
+abstract class LookupAdapter extends RBuiltinNode.Arg3 implements Lookup {
+    @Child protected ExtractNativeCallInfoNode extractSymbolInfo = ExtractNativeCallInfoNodeGen.create();
 
     protected static class UnimplementedExternal extends RExternalBuiltinNode {
         private final String name;
@@ -87,11 +92,9 @@ abstract class LookupAdapter extends RBuiltinNode {
         }
     }
 
-    protected abstract RExternalBuiltinNode lookupBuiltin(RList symbol);
-
     private static final String UNKNOWN_EXTERNAL_BUILTIN = "UNKNOWN_EXTERNAL_BUILTIN";
 
-    protected static String lookupName(RList symbol) {
+    public static String lookupName(RList symbol) {
         CompilerAsserts.neverPartOfCompilation();
         if (symbol.getNames() != null) {
             RAbstractStringVector names = symbol.getNames();
@@ -106,32 +109,28 @@ abstract class LookupAdapter extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    protected RuntimeException fallback(Object symbol) {
+    protected static RuntimeException fallback(Lookup lookup, Object symbol) {
         String name = null;
         if (symbol instanceof RList) {
             name = lookupName((RList) symbol);
             name = name == UNKNOWN_EXTERNAL_BUILTIN ? null : name;
-            if (name != null && lookupBuiltin((RList) symbol) != null) {
+            if (name != null && lookup.lookupBuiltin((RList) symbol) != null) {
                 /*
                  * if we reach this point, then the cache saw a different value for f. the lists
                  * that contain the information about native calls are never expected to change.
                  */
-                throw RInternalError.shouldNotReachHere("fallback reached for " + getRBuiltin().name() + " " + name);
+                throw RInternalError.shouldNotReachHere("fallback reached for " + lookup + " " + name);
             }
         }
-        throw RError.nyi(this, getRBuiltin().name() + " specialization failure: " + (name == null ? "<unknown>" : name));
-    }
-
-    protected NativeCallInfo extractSymbolInfo(VirtualFrame frame, RList symbol) {
-        return (NativeCallInfo) extractSymbolInfoNode.execute(frame, symbol);
+        throw RError.nyi((RBaseNode) lookup, lookup + " specialization failure: " + (name == null ? "<unknown>" : name));
     }
 
-    protected String checkPackageArg(Object rPackage) {
+    public static String checkPackageArg(Object rPackage) {
         String libName = null;
         if (!(rPackage instanceof RMissing)) {
             libName = RRuntime.asString(rPackage);
             if (libName == null) {
-                throw error(RError.Message.ARGUMENT_MUST_BE_STRING, "PACKAGE");
+                throw RError.error(RError.SHOW_CALLER, RError.Message.ARGUMENT_MUST_BE_STRING, "PACKAGE");
             }
         }
         return libName;
@@ -147,10 +146,10 @@ abstract class LookupAdapter extends RBuiltinNode {
         @Child private ExtractVectorNode packageExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
         @Child private ExtractVectorNode infoExtract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true);
 
-        protected abstract Object execute(VirtualFrame frame, RList symbol);
+        protected abstract NativeCallInfo execute(VirtualFrame frame, RList symbol);
 
         @Specialization
-        protected Object extractNativeCallInfo(VirtualFrame frame, RList symbol) {
+        protected NativeCallInfo extractNativeCallInfo(VirtualFrame frame, RList symbol) {
             if (nameExtract == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 nameExtract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true));
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 c1677176cef18c56b61b41750990a6092568abf3..f1c99a37f020f0390bb88803583aa6f11cf51e06 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
@@ -83,7 +83,7 @@ abstract class AccessFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
 }
 
 @RBuiltin(name = "$", kind = PRIMITIVE, parameterNames = {"", ""}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class AccessField extends RBuiltinNode {
+public abstract class AccessField extends RBuiltinNode.Arg2 {
 
     @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.FIELD_SUBSCRIPT, true);
 
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 0a795bc055540c7147a42bad06815910360a9ed0..90d1260e9a5aedc21d8b9eb2f426d874d762e37b 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.builtins.RBehavior;
 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 {
+public abstract class AssignBuiltin extends RBuiltinNode.Arg2 {
 
     static {
         Casts.noCasts(AssignBuiltin.class);
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 bf68624ef5f609dd6c888a7f76304d0614c72b2f..f35dc6cff103578b9bbac9e4bfab330c69551a64 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.builtins.RBehavior;
 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 {
+public abstract class AssignBuiltinEq extends RBuiltinNode.Arg2 {
 
     static {
         Casts.noCasts(AssignBuiltinEq.class);
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 3ef3d4676c026013f848a1915a558d707bb0b333..35ccfe7cc34a09d1c1a098678d456f83f6e653f2 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.RVisibility;
 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 {
+public abstract class AssignOuterBuiltin extends RBuiltinNode.Arg2 {
 
     static {
         Casts.noCasts(AssignOuterBuiltin.class);
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 67c223259eb84f371fafe6d614ddadd0343f89fa..2db00345ee186afe2c0f3d3d9f3e0ce4713e91e0 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
@@ -33,7 +33,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "{", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-public abstract class BraceBuiltin extends RBuiltinNode {
+public abstract class BraceBuiltin extends RBuiltinNode.Arg1 {
 
     static {
         noCasts(BraceBuiltin.class);
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 e1aab99445af84d0a01e5c0d580f800710a7e673..aeea494ef8219d3633a887e6d3ac1b305e8a43c8 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
@@ -31,7 +31,8 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "break", kind = PRIMITIVE, parameterNames = {"x"}, behavior = COMPLEX)
-public abstract class BreakBuiltin extends RBuiltinNode {
+public abstract class BreakBuiltin extends RBuiltinNode.Arg1 {
+
     static {
         Casts.noCasts(BreakBuiltin.class);
     }
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 cbb0e5ae48f722a4607aa56e00856a21d0b5e955..c9309ab8700e8603c63c56cd4da039820d225cb3 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 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 {
+public abstract class ForBuiltin extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(ForBuiltin.class);
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 c81176d2e3b68fedf1e98e2c73f7be47e3abacfa..3909ffbb92edc496f1e07f724252dcc77cd3df50 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
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = READS_FRAME)
-public abstract class FunctionBuiltin extends RBuiltinNode {
+public abstract class FunctionBuiltin extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(FunctionBuiltin.class);
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 9920963799facd175653a3e88677689cedfb358e..0865d2a4e83f619c59b33873c9ae33e0ad97f6ce 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 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 {
+public abstract class IfBuiltin extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(IfBuiltin.class);
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 16830767a1e7cea8463f02ff5b6f568e169083cf..0fc3d4127437b9b1e9878ddaf672ad86e5102d43 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "next", kind = PRIMITIVE, parameterNames = {"x"}, behavior = COMPLEX)
-public abstract class NextBuiltin extends RBuiltinNode {
+public abstract class NextBuiltin extends RBuiltinNode.Arg1 {
 
     static {
         noCasts(NextBuiltin.class);
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 08d6f1a6243c1359527a535f4e7d1eae0f508238..dd90c743d349537dd358bb36d417c7b0ff13368a 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
@@ -50,7 +50,7 @@ final class ParensSpecial extends RNode {
 }
 
 @RBuiltin(name = "(", kind = PRIMITIVE, parameterNames = {""}, visibility = ON, behavior = PURE)
-public final class ParenBuiltin extends RBuiltinNode {
+public final class ParenBuiltin extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(ParenBuiltin.class);
@@ -64,7 +64,7 @@ public final class ParenBuiltin extends RBuiltinNode {
     }
 
     @Override
-    public Object executeBuiltin(VirtualFrame frame, Object... args) {
-        return args[0];
+    public Object execute(VirtualFrame frame, Object arg) {
+        return arg;
     }
 }
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 46239fcbf51a8063ef0c8eeaf23cb00bd788a48e..73ea958d487584dad35969a4e6d8bca087ab506d 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
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 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 {
+public abstract class RepeatBuiltin extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(RepeatBuiltin.class);
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 daf9a1dac7972b88ad00e41f2d638c479991a897..6a4401c32b79b928e96485eeb3e981b5d7f98d4e 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
@@ -185,7 +185,7 @@ abstract class SubscriptSpecial2 extends SubscriptSpecial2Base {
 
 @RBuiltin(name = "[[", kind = PRIMITIVE, parameterNames = {"x", "...", "exact", "drop"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 @TypeSystemReference(RTypes.class)
-public abstract class Subscript extends RBuiltinNode {
+public abstract class Subscript extends RBuiltinNode.Arg4 {
 
     @RBuiltin(name = ".subset2", kind = PRIMITIVE, parameterNames = {"x", "...", "exact", "drop"}, behavior = PURE)
     public abstract class DefaultBuiltin {
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 0042a04609928bc305b4de17829dd9dbb13c934e..18cafe6488e0dd20f28e1d68cf716460f886c917 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
@@ -109,7 +109,7 @@ abstract class SubsetSpecial2 extends SubscriptSpecial2Base {
 }
 
 @RBuiltin(name = "[", kind = PRIMITIVE, parameterNames = {"x", "...", "drop"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class Subset extends RBuiltinNode {
+public abstract class Subset extends RBuiltinNode.Arg3 {
 
     @RBuiltin(name = ".subset", kind = PRIMITIVE, parameterNames = {"", "...", "drop"}, behavior = PURE)
     public abstract class DefaultBuiltin {
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 474cd495bb52ab09124713dc6fee51015a3bc19b..14828d57c5abf1e0289ee25ddfb4148238b1cf4a 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
@@ -48,7 +48,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * argument is missing, i.e. {@code ~ x} result in {@code `~`(x)}.
  */
 @RBuiltin(name = "~", kind = PRIMITIVE, parameterNames = {"x", "y"}, nonEvalArgs = {0, 1}, behavior = READS_FRAME)
-public abstract class Tilde extends RBuiltinNode {
+public abstract class Tilde extends RBuiltinNode.Arg2 {
 
     private static final RStringVector FORMULA_CLASS = RDataFactory.createStringVectorFromScalar(RRuntime.FORMULA_CLASS);
 
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 5d55e54d97e4fbd8b74b8d5161a96936aa8c1670..3d1e5f25835fc4646394354aa6611cd29187b945 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
@@ -114,7 +114,7 @@ abstract class UpdateFieldSpecial extends SpecialsUtils.ListFieldSpecialBase {
 }
 
 @RBuiltin(name = "$<-", kind = PRIMITIVE, parameterNames = {"", "", "value"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class UpdateField extends RBuiltinNode {
+public abstract class UpdateField extends RBuiltinNode.Arg3 {
 
     @Child private ReplaceVectorNode update = ReplaceVectorNode.create(ElementAccessMode.FIELD_SUBSCRIPT, true);
     @Child private CastListNode castList;
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 3eb7a8278f6e023916b329922eba2334bf69ab10..e9d5efbbd294b8651f34b7d37bf02086cf151d5b 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
@@ -161,7 +161,7 @@ abstract class UpdateSubscriptSpecial2 extends SubscriptSpecial2Common {
 }
 
 @RBuiltin(name = "[[<-", kind = PRIMITIVE, parameterNames = {"", "..."}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class UpdateSubscript extends RBuiltinNode {
+public abstract class UpdateSubscript extends RBuiltinNode.Arg2 {
 
     @Child private ReplaceVectorNode replaceNode = ReplaceVectorNode.create(ElementAccessMode.SUBSCRIPT, false);
 
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 445e8417ca55a29f90b71a7bbe09477667006e06..450506ba103fbd76b18243d9b84cfad7e8ec20ef 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
@@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
 @RBuiltin(name = "[<-", kind = PRIMITIVE, parameterNames = {"..."}, dispatch = INTERNAL_GENERIC, behavior = PURE)
-public abstract class UpdateSubset extends RBuiltinNode {
+public abstract class UpdateSubset extends RBuiltinNode.Arg1 {
 
     @Child private ReplaceVectorNode replaceNode = ReplaceVectorNode.create(ElementAccessMode.SUBSET, false);
     private final ConditionProfile argsLengthLargerThanOneProfile = ConditionProfile.createBinaryProfile();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/WhileBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/WhileBuiltin.java
index 405853e771551d311112f581eb697ac413ee7431..680ad83d25ad9c1a6c02c11ed5157d58fc4e1519 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/WhileBuiltin.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/WhileBuiltin.java
@@ -33,7 +33,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "while", visibility = OFF, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
-public abstract class WhileBuiltin extends RBuiltinNode {
+public abstract class WhileBuiltin extends RBuiltinNode.Arg1 {
     static {
         noCasts(WhileBuiltin.class);
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/ContextSystemFunctionFactory.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/ContextSystemFunctionFactory.java
index a65602428e16c18ff456d1962ae2c505078b4be6..cfb7d5c70ae05cad44e312fce61f577d0eeb8888 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/ContextSystemFunctionFactory.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/system/ContextSystemFunctionFactory.java
@@ -59,7 +59,7 @@ public class ContextSystemFunctionFactory extends SystemFunctionFactory {
         @Specialization
         protected Object systemFunction(VirtualFrame frame, RAbstractStringVector args, RAbstractStringVector env, boolean intern) {
             initContextRNode();
-            Object result = contextRNode.executeBuiltin(frame, args, env, intern);
+            Object result = contextRNode.execute(frame, args, env, intern);
             return result;
         }
     }
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 5d0ab412d03e5514e51f8d39884a29be19cb3821..3fbbfa50905c650e08e36cb383b340948cfc3085 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = "system", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"command", "intern"}, behavior = COMPLEX)
-public abstract class SystemFunction extends RBuiltinNode {
+public abstract class SystemFunction extends RBuiltinNode.Arg2 {
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
     static {
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 58ec42838ec390e5b089ad19bfcf1620112fbe46..25883797eef9b10da63e2df558e92940ffeafdf3 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
@@ -36,6 +36,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.vm.PolyglotEngine;
@@ -86,7 +87,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.context.get", kind = PRIMITIVE, parameterNames = {}, behavior = READS_STATE)
-    public abstract static class Get extends RBuiltinNode {
+    public abstract static class Get extends RBuiltinNode.Arg0 {
         @Specialization
         @TruffleBoundary
         protected TruffleObject get() {
@@ -101,7 +102,7 @@ public class FastRContext {
      *
      */
     @RBuiltin(name = ".fastr.context.spawn", kind = PRIMITIVE, parameterNames = {"exprs", "pc", "kind"}, behavior = COMPLEX)
-    public abstract static class Spawn extends RBuiltinNode {
+    public abstract static class Spawn extends RBuiltinNode.Arg3 {
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
@@ -133,7 +134,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.context.join", visibility = OFF, kind = PRIMITIVE, parameterNames = {"handle"}, behavior = COMPLEX)
-    public abstract static class Join extends RBuiltinNode {
+    public abstract static class Join extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Join.class);
@@ -173,7 +174,7 @@ public class FastRContext {
      * attribute "error" if the evaluation threw an exception, in which case the result will be NA.
      */
     @RBuiltin(name = ".fastr.context.eval", kind = PRIMITIVE, parameterNames = {"exprs", "pc", "kind"}, behavior = COMPLEX)
-    public abstract static class Eval extends RBuiltinNode {
+    public abstract static class Eval extends RBuiltinNode.Arg3 {
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
@@ -224,7 +225,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.context.r", kind = PRIMITIVE, visibility = OFF, parameterNames = {"args", "env", "intern"}, behavior = COMPLEX)
-    public abstract static class R extends RBuiltinNode {
+    public abstract static class R extends RBuiltinNode.Arg3 {
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
@@ -237,6 +238,8 @@ public class FastRContext {
             casts.arg("intern").asLogicalVector().findFirst().map(toBoolean());
         }
 
+        public abstract Object execute(VirtualFrame frame, RAbstractStringVector args, RAbstractStringVector env, boolean intern);
+
         @Specialization
         @TruffleBoundary
         protected Object r(RAbstractStringVector args, RAbstractStringVector env, boolean intern) {
@@ -257,7 +260,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.context.rscript", kind = PRIMITIVE, visibility = OFF, parameterNames = {"args", "env", "intern"}, behavior = COMPLEX)
-    public abstract static class Rscript extends RBuiltinNode {
+    public abstract static class Rscript extends RBuiltinNode.Arg3 {
 
         public abstract Object execute(RAbstractStringVector args, RAbstractStringVector env, boolean intern);
 
@@ -291,7 +294,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.channel.create", kind = PRIMITIVE, parameterNames = {"key"}, behavior = COMPLEX)
-    public abstract static class CreateChannel extends RBuiltinNode {
+    public abstract static class CreateChannel extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(CreateChannel.class);
@@ -306,7 +309,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.channel.get", kind = PRIMITIVE, parameterNames = {"key"}, behavior = COMPLEX)
-    public abstract static class GetChannel extends RBuiltinNode {
+    public abstract static class GetChannel extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(GetChannel.class);
@@ -321,7 +324,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.channel.close", visibility = OFF, kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
-    public abstract static class CloseChannel extends RBuiltinNode {
+    public abstract static class CloseChannel extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(CloseChannel.class);
@@ -337,7 +340,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.channel.send", visibility = OFF, kind = PRIMITIVE, parameterNames = {"id", "data"}, behavior = COMPLEX)
-    public abstract static class ChannelSend extends RBuiltinNode {
+    public abstract static class ChannelSend extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(ChannelSend.class);
@@ -353,7 +356,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.channel.receive", kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
-    public abstract static class ChannelReceive extends RBuiltinNode {
+    public abstract static class ChannelReceive extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(ChannelReceive.class);
@@ -368,7 +371,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.channel.poll", kind = PRIMITIVE, parameterNames = {"id"}, behavior = COMPLEX)
-    public abstract static class ChannelPoll extends RBuiltinNode {
+    public abstract static class ChannelPoll extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(ChannelPoll.class);
@@ -383,7 +386,7 @@ public class FastRContext {
     }
 
     @RBuiltin(name = ".fastr.channel.select", kind = PRIMITIVE, parameterNames = {"ids"}, behavior = COMPLEX)
-    public abstract static class ChannelSelect extends RBuiltinNode {
+    public abstract static class ChannelSelect extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(ChannelSelect.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 6c4ea7922d51e52c3748273d128cf4dc82e18bed..2ab883be50ae2b95d5a443feca382c2b38d9168f 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 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 {
+public abstract class FastRDebug extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(FastRDebug.class);
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 5b76a6ac968905d6039b7e8c80a0707e08b4a6ca..5f3b6b3a2afc833b6cfbeb9f1086c2cb5865d1c2 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
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 
 @RBuiltin(name = ".fastr.identity", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
-public abstract class FastRIdentity extends RBuiltinNode {
+public abstract class FastRIdentity extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(FastRIdentity.class);
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 39cb3d17be08313cfcb2b864857c22afde8472db..5454bf483eb322eb41c4b4949bd4fbe4eba7395f 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
  * Just a convenient way to inspect values in the Java debugger from the R shell.
  */
 @RBuiltin(name = ".fastr.inspect", visibility = OFF, kind = PRIMITIVE, parameterNames = {"..."}, behavior = COMPLEX)
-public abstract class FastRInspect extends RBuiltinNode {
+public abstract class FastRInspect extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(FastRInspect.class);
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 fcc48d956d3e48d6b64105079cc0d80038ddc58d..912beabdbf0da3918da1bdfbe295e03b7822cea5 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
@@ -73,7 +73,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 public class FastRInterop {
 
     @RBuiltin(name = ".fastr.interop.eval", visibility = OFF, kind = PRIMITIVE, parameterNames = {"mimeType", "source"}, behavior = COMPLEX)
-    public abstract static class Eval extends RBuiltinNode {
+    public abstract static class Eval extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(Eval.class);
@@ -113,7 +113,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.interop.evalFile", visibility = OFF, kind = PRIMITIVE, parameterNames = {"path", "mimeType"}, behavior = COMPLEX)
-    public abstract static class EvalFile extends RBuiltinNode {
+    public abstract static class EvalFile extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(EvalFile.class);
@@ -153,7 +153,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.interop.export", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name", "value"}, behavior = COMPLEX)
-    public abstract static class Export extends RBuiltinNode {
+    public abstract static class Export extends RBuiltinNode.Arg2 {
 
         static {
             Casts casts = new Casts(Export.class);
@@ -185,7 +185,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.interop.import", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX)
-    public abstract static class Import extends RBuiltinNode {
+    public abstract static class Import extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(Import.class);
@@ -204,7 +204,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.interop.hasSize", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
-    public abstract static class HasSize extends RBuiltinNode {
+    public abstract static class HasSize extends RBuiltinNode.Arg1 {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.HAS_SIZE.createNode();
 
@@ -219,7 +219,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.interop.isNull", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
-    public abstract static class IsNull extends RBuiltinNode {
+    public abstract static class IsNull extends RBuiltinNode.Arg1 {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.IS_NULL.createNode();
 
@@ -234,7 +234,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.interop.isExecutable", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
-    public abstract static class IsExecutable extends RBuiltinNode {
+    public abstract static class IsExecutable extends RBuiltinNode.Arg1 {
 
         @Child private Node node = com.oracle.truffle.api.interop.Message.IS_EXECUTABLE.createNode();
 
@@ -249,7 +249,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.interop.toBoolean", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
-    public abstract static class ToBoolean extends RBuiltinNode {
+    public abstract static class ToBoolean extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(ToBoolean.class);
@@ -263,7 +263,7 @@ public class FastRInterop {
     }
 
     @RBuiltin(name = ".fastr.java.class", visibility = ON, kind = PRIMITIVE, parameterNames = {"class"}, behavior = COMPLEX)
-    public abstract static class JavaClass extends RBuiltinNode {
+    public abstract static class JavaClass extends RBuiltinNode.Arg1 {
 
         static {
             Casts casts = new Casts(JavaClass.class);
@@ -283,7 +283,7 @@ public class FastRInterop {
 
     @ImportStatic({com.oracle.truffle.api.interop.Message.class, RRuntime.class})
     @RBuiltin(name = ".fastr.interop.new", visibility = ON, kind = PRIMITIVE, parameterNames = {"class", "..."}, behavior = COMPLEX)
-    public abstract static class InteropNew extends RBuiltinNode {
+    public abstract static class InteropNew extends RBuiltinNode.Arg2 {
 
         static {
             Casts.noCasts(InteropNew.class);
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 b0a67b019a9f631eb6b4575471ce6ec2f498df21..ebb579bb12c6d3be3d656752dd70eb0af23610c3 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
@@ -61,7 +61,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  * {@code Rpkgsource} directory., for use by e.g., a source-level debugger.
  */
 @RBuiltin(name = ".fastr.pkgsource", kind = PRIMITIVE, visibility = OFF, parameterNames = {"pkgs", "verbose"}, behavior = COMPLEX)
-public abstract class FastRPkgSource extends RBuiltinNode {
+public abstract class FastRPkgSource extends RBuiltinNode.Arg2 {
     public static final String PKGSOURCE_PROJECT = "Rpkgsource";
     private static final String SLASH_SWAP = "_slash_";
 
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 a9e8cee05edafc523f5399c3ee63f76324ee33d0..b6634b88c34d0aff430a638615bfd39806ce32c3 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.data.RShareable;
  * for permanent shared
  */
 @RBuiltin(name = ".fastr.refcountinfo", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
-public abstract class FastRRefCountInfo extends RBuiltinNode {
+public abstract class FastRRefCountInfo extends RBuiltinNode.Arg1 {
 
     static {
         Casts.noCasts(FastRRefCountInfo.class);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSlotAssign.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSlotAssign.java
index 4bf687e14fe56a99ad7892c2f024656429c40541..a4bdf0126efc6f58423c856f6af5bdcc6e0c83e1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSlotAssign.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSlotAssign.java
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RMissing;
 
 @RBuiltin(name = ".fastr.methods.slotassign", visibility = ON, kind = PRIMITIVE, parameterNames = {"object", "name", "check", "value"}, behavior = COMPLEX)
-public abstract class FastRSlotAssign extends RBuiltinNode {
+public abstract class FastRSlotAssign extends RBuiltinNode.Arg4 {
 
     static {
         Casts casts = new Casts(FastRSlotAssign.class);
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 f2b4d2b4d54af8bc4024cea49df6cf1b5b5b8679..b7179ade00d55bd5bad8fd8e03c96728bb9837a9 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = ".fastr.stacktrace", visibility = OFF, kind = PRIMITIVE, parameterNames = {"print.frame.contents"}, behavior = COMPLEX)
-public abstract class FastRStackTrace extends RBuiltinNode {
+public abstract class FastRStackTrace extends RBuiltinNode.Arg1 {
 
     @Override
     public Object[] getDefaultParameterValues() {
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 fd22a2f70edd249d49404eceac26682b0faa3eb0..458fa6ebeff90250e215b59b64ec750d1755edde 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
@@ -73,7 +73,7 @@ public class FastRStats {
     }
 
     @RBuiltin(name = ".fastr.prof.attr", visibility = OFF, kind = PRIMITIVE, parameterNames = {"filename", "append"}, behavior = COMPLEX)
-    public abstract static class FastRProfAttr extends RBuiltinNode implements AttributeTracer.Listener {
+    public abstract static class FastRProfAttr extends RBuiltinNode.Arg2 implements AttributeTracer.Listener {
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{"Rprofattr.out", RRuntime.LOGICAL_FALSE};
@@ -158,7 +158,7 @@ public class FastRStats {
     }
 
     @RBuiltin(name = ".fastr.stats.typecounts", visibility = OFF, kind = PRIMITIVE, parameterNames = {"filename", "append"}, behavior = COMPLEX)
-    public abstract static class FastRProfTypecounts extends RBuiltinNode implements RDataFactory.Listener {
+    public abstract static class FastRProfTypecounts extends RBuiltinNode.Arg2 implements RDataFactory.Listener {
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{"Rproftypecounts.out", RRuntime.LOGICAL_FALSE};
@@ -289,7 +289,7 @@ public class FastRStats {
     }
 
     @RBuiltin(name = ".fastr.stats.funcounts", visibility = OFF, kind = PRIMITIVE, parameterNames = {"filename", "append", "timing", "threshold", "histograms"}, behavior = COMPLEX)
-    public abstract static class FastRProfFuncounts extends RBuiltinNode {
+    public abstract static class FastRProfFuncounts extends RBuiltinNode.Arg5 {
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{"Rproffuncounts.out", RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE, 0, RRuntime.LOGICAL_FALSE};
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 5e1c4403e3b1e3ae57f40509aedaa86a2794bf82..41e42f0a135329bf7ec09355c304c36d8f4b5aa1 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
@@ -66,7 +66,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor;
  *
  */
 @RBuiltin(name = ".fastr.syntaxtree", visibility = OFF, kind = PRIMITIVE, parameterNames = {"func", "visitMode", "printSource", "printTags"}, behavior = IO)
-public abstract class FastRSyntaxTree extends RBuiltinNode {
+public abstract class FastRSyntaxTree extends RBuiltinNode.Arg4 {
 
     @Override
     public Object[] getDefaultParameterValues() {
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 f1a6f7d4cc72e298c8b76149f225c851a0d5b00a..648bb944fc34d0a3d91b009ddd55c0665ad92d95 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
 
 @RBuiltin(name = ".fastr.throw", kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX)
-public abstract class FastRThrowIt extends RBuiltinNode {
+public abstract class FastRThrowIt extends RBuiltinNode.Arg1 {
 
     static {
         Casts casts = new Casts(FastRThrowIt.class);
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 1e7072ac50018c6b97e0ebbc580c95b0899c3b2f..66cc11355605455f15f5f63a157594592a84f7ab 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
@@ -56,6 +56,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * This a FastR-specific version of the standard {@code trace} function which uses the
@@ -66,7 +67,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
  */
 public class FastRTrace {
 
-    protected abstract static class Helper extends RBuiltinNode {
+    static final class Helper extends RBaseNode {
         @Child private GetFunctions.Get getNode;
         @Child private EnvFunctions.TopEnv topEnv;
         @Child private FrameFunctions.ParentFrame parentFrame;
@@ -80,7 +81,7 @@ public class FastRTrace {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 parentFrame = insert(ParentFrameNodeGen.create());
             }
-            return topEnv.executeBuiltin(frame, parentFrame.execute(frame, 1), RNull.instance);
+            return topEnv.execute(frame, parentFrame.execute(frame, 1), RNull.instance);
         }
 
         protected Object getFunction(VirtualFrame frame, Object what, Object where) {
@@ -88,7 +89,7 @@ public class FastRTrace {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 getNode = insert(GetNodeGen.create());
             }
-            return getNode.executeBuiltin(frame, what, where, RType.Function.getName(), true);
+            return getNode.execute(frame, what, where, RType.Function.getName(), true);
         }
 
         protected void checkWhat(Object what) {
@@ -112,11 +113,12 @@ public class FastRTrace {
     }
 
     @RBuiltin(name = ".fastr.trace", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"what", "tracer", "exit", "at", "print", "signature", "where"}, behavior = COMPLEX)
-    public abstract static class Trace extends Helper {
+    public abstract static class Trace extends RBuiltinNode.Arg7 {
 
         @Child private TraceFunctions.PrimTrace primTrace;
         @Child private CastLogicalNode castLogical;
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+        @Child private Helper helper = new Helper();
 
         static {
             Casts.noCasts(Trace.class);
@@ -125,16 +127,16 @@ public class FastRTrace {
         @Specialization
         protected Object trace(VirtualFrame frame, Object whatObj, Object tracer, Object exit, Object at, Object printObj, Object signature, Object whereObj) {
             Object what = whatObj;
-            checkWhat(what);
+            helper.checkWhat(what);
             Object where = whereObj;
             if (where == RMissing.instance) {
-                where = getWhere(frame);
+                where = helper.getWhere(frame);
             }
             String funcName = RRuntime.asString(what);
             if (funcName != null) {
-                what = getFunction(frame, what, where);
+                what = helper.getFunction(frame, what, where);
             }
-            RFunction func = checkFunction(what);
+            RFunction func = helper.checkFunction(what);
 
             if (tracer == RMissing.instance && exit == RMissing.instance && at == RMissing.instance && printObj == RMissing.instance && signature == RMissing.instance) {
                 // simple case, nargs() == 1, corresponds to .primTrace that has invisible output
@@ -143,7 +145,7 @@ public class FastRTrace {
                     primTrace = insert(PrimTraceNodeGen.create());
                 }
 
-                Object result = primTrace.executeBuiltin(frame, func);
+                Object result = primTrace.execute(frame, func);
                 visibility.execute(frame, false);
                 return result;
             }
@@ -181,9 +183,10 @@ public class FastRTrace {
     }
 
     @RBuiltin(name = ".fastr.untrace", visibility = OFF, kind = PRIMITIVE, parameterNames = {"what", "signature", "where"}, behavior = COMPLEX)
-    public abstract static class Untrace extends Helper {
+    public abstract static class Untrace extends RBuiltinNode.Arg3 {
 
         @Child private TraceFunctions.PrimUnTrace primUnTrace;
+        @Child private Helper helper = new Helper();
 
         static {
             Casts.noCasts(Untrace.class);
@@ -192,22 +195,22 @@ public class FastRTrace {
         @Specialization
         protected Object untrace(VirtualFrame frame, Object whatObj, Object signature, Object whereObj) {
             Object what = whatObj;
-            checkWhat(what);
+            helper.checkWhat(what);
             Object where = whereObj;
             if (where == RMissing.instance) {
-                where = getWhere(frame);
+                where = helper.getWhere(frame);
             }
             String funcName = RRuntime.asString(what);
             if (funcName != null) {
-                what = getFunction(frame, what, where);
+                what = helper.getFunction(frame, what, where);
             }
-            RFunction func = checkFunction(what);
+            RFunction func = helper.checkFunction(what);
             if (signature == RMissing.instance) {
                 if (primUnTrace == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
                     primUnTrace = insert(PrimUnTraceNodeGen.create());
                 }
-                primUnTrace.executeBuiltin(frame, func);
+                primUnTrace.execute(frame, func);
             } else {
                 throw RError.nyi(this, "method tracing");
             }
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 7071bb26a0b839e61a49f0997f1738cff88abfd1..85284f52cdfba70b385777f05b68bebe11bcab2c 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
@@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RMissing;
 
 @RBuiltin(name = ".fastr.tree", visibility = OFF, kind = PRIMITIVE, parameterNames = {"func", "verbose"}, behavior = IO)
-public abstract class FastRTree extends RBuiltinNode {
+public abstract class FastRTree extends RBuiltinNode.Arg2 {
     @Override
     public Object[] getDefaultParameterValues() {
         return new Object[]{RMissing.instance, RRuntime.LOGICAL_FALSE};
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTreeStats.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTreeStats.java
index e40645a046c4dde52d735a628aa6e7397fd51f2e..75a82d67668729717c7458700c24757ba51b08f8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTreeStats.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTreeStats.java
@@ -46,7 +46,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @RBuiltin(name = ".fastr.treestats", kind = PRIMITIVE, parameterNames = {"obj"}, behavior = COMPLEX)
-public abstract class FastRTreeStats extends RBuiltinNode {
+public abstract class FastRTreeStats extends RBuiltinNode.Arg1 {
 
     private static final RStringVector COLNAMES = RDataFactory.createStringVector(new String[]{"Total", "Syntax", "Non-Syntax"}, RDataFactory.COMPLETE_VECTOR);
 
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 45a57b19326df2fafe3f82f8218977900929712a..53cf1f0e42896f1d33eff6993c57d6e7d8427cb7 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
@@ -41,7 +41,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
  * message.
  */
 @RBuiltin(name = ".fastr.try", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX)
-public abstract class FastRTry extends RBuiltinNode {
+public abstract class FastRTry extends RBuiltinNode.Arg1 {
     @Child private RExplicitCallNode call = RExplicitCallNode.create();
 
     static {
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 badecba152c43957f7fbbe4089fd0d6360c36bbb..d7d7701f673221a3b83aa0f34108c16b98969fb6 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
@@ -36,7 +36,7 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
  * directly this Fortran routine.
  */
 @RBuiltin(name = ".fastr.dqrls", visibility = OFF, kind = PRIMITIVE, parameterNames = {"x", "n", "p", "y", "ny", "tol", "coeff"}, behavior = PURE)
-public abstract class FastrDqrls extends RBuiltinNode {
+public abstract class FastrDqrls extends RBuiltinNode.Arg7 {
     @Child private RApplRFFI.DqrlsNode dqrlsNode = RFFIFactory.getRFFI().getRApplRFFI().createDqrlsNode();
 
     private static final String[] NAMES = new String[]{"qr", "coefficients", "residuals", "effects", "rank", "pivot", "qraux", "tol", "pivoted"};
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
index 7ba9410133cc0e33392bf4e59cf21fcc370f0d94..2b5c1143dd71930a92714d9081f37c5b31c34843 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
@@ -387,6 +387,6 @@ public class BinaryArithmeticNodeTest extends BinaryVectorTest {
 
     private static NodeHandle<BinaryArithmeticNode> create(BinaryArithmeticFactory factory) {
         return createHandle(BinaryArithmeticNode.create(factory, null),
-                        (node, args) -> node.executeBuiltin(null, args[0], args[1]));
+                        (node, args) -> node.execute(args[0], args[1]));
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RRootNode.java
index 929e53938623402ab75e0db4ae3dfa7b0ab7a697..d04204e0e385de54e1fe66c533b39e74cc27921d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RRootNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RRootNode.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.r.nodes.builtin.RBuiltinFactory;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
-import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.HasSignature;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.builtins.FastPathFactory;
@@ -46,16 +45,10 @@ public abstract class RRootNode extends RootNode implements HasSignature {
 
     private final ConditionProfile irregularFrameProfile = ConditionProfile.createBinaryProfile();
 
-    /**
-     * The formal arguments this function is supposed to take.
-     */
-    private final FormalArguments formalArguments;
-
     private FastPathFactory fastPath;
 
-    protected RRootNode(FormalArguments formalArguments, FrameDescriptor frameDescriptor, FastPathFactory fastPath) {
+    protected RRootNode(FrameDescriptor frameDescriptor, FastPathFactory fastPath) {
         super(RContext.getRForeignAccessFactory().getTruffleLanguage(), RSyntaxNode.SOURCE_UNAVAILABLE, frameDescriptor);
-        this.formalArguments = formalArguments;
         this.fastPath = fastPath;
     }
 
@@ -66,25 +59,6 @@ public abstract class RRootNode extends RootNode implements HasSignature {
         RArguments.setIsIrregular(vf, irregularFrameProfile.profile(RArguments.getIsIrregular(vf)));
     }
 
-    /**
-     * @return The number of parameters this functions expects
-     */
-    public final int getParameterCount() {
-        return formalArguments.getSignature().getLength();
-    }
-
-    /**
-     * @return {@link #formalArguments}
-     */
-    public final FormalArguments getFormalArguments() {
-        return formalArguments;
-    }
-
-    @Override
-    public final ArgumentsSignature getSignature() {
-        return formalArguments.getSignature();
-    }
-
     public final FastPathFactory getFastPath() {
         return fastPath;
     }
@@ -93,6 +67,8 @@ public abstract class RRootNode extends RootNode implements HasSignature {
         this.fastPath = fastPath;
     }
 
+    public abstract FormalArguments getFormalArguments();
+
     public abstract boolean needsSplitting();
 
     public abstract boolean containsDispatch();
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 96aa278a5aa36b964496a612eb13455baede1f39..56f24c6840969e6049dfd536a99694f3c015011e 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
@@ -55,24 +55,26 @@ import com.oracle.truffle.r.runtime.ops.UnaryArithmeticFactory;
  * operation is implemented by factory object given as a constructor parameter, e.g.
  * {@link com.oracle.truffle.r.runtime.ops.BinaryArithmetic.Add}
  */
-public abstract class BinaryArithmeticNode extends RBuiltinNode {
+public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 {
 
     protected static final int CACHE_LIMIT = 5;
 
     protected final BinaryArithmeticFactory binary;
     private final UnaryArithmeticFactory unary;
 
-    public BinaryArithmeticNode(BinaryArithmeticFactory binaryFactory, UnaryArithmeticFactory unaryFactory) {
-        this.binary = binaryFactory;
-        this.unary = unaryFactory;
-    }
-
     static {
         Casts casts = new Casts(BinaryArithmeticNode.class);
         casts.arg(0).boxPrimitive();
         casts.arg(1).boxPrimitive();
     }
 
+    public BinaryArithmeticNode(BinaryArithmeticFactory binaryFactory, UnaryArithmeticFactory unaryFactory) {
+        this.binary = binaryFactory;
+        this.unary = unaryFactory;
+    }
+
+    public abstract Object execute(Object left, Object right);
+
     @Override
     public RBaseNode getErrorContext() {
         return this;
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 21088940da2f1b8954af17a0a666ec8d2f7f12a8..1f317668577066be9db826c1ae0ee1dce1e65fa2 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
@@ -57,7 +57,7 @@ import com.oracle.truffle.r.runtime.ops.BooleanOperationFactory;
  * operation is implemented by factory object given as a constructor parameter, e.g.
  * {@link com.oracle.truffle.r.runtime.ops.BinaryLogic.And}.
  */
-public abstract class BinaryBooleanNode extends RBuiltinNode {
+public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 {
 
     protected static final int CACHE_LIMIT = 5;
 
@@ -86,6 +86,7 @@ public abstract class BinaryBooleanNode extends RBuiltinNode {
         return factory == BinaryLogic.AND || factory == BinaryLogic.OR;
     }
 
+    @Override
     public abstract Object execute(VirtualFrame frame, Object left, Object right);
 
     public static BinaryBooleanNode create(BooleanOperationFactory 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 3026310ff21bd27440abc320c7cb1fd058d55a31..444696a3f70eddfded9e68f72af65a821195e2c9 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
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.ops.BooleanOperation;
 import com.oracle.truffle.r.runtime.ops.BooleanOperationFactory;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
-public abstract class BinaryBooleanScalarNode extends RBuiltinNode {
+public abstract class BinaryBooleanScalarNode extends RBuiltinNode.Arg2 {
 
     /*
      * As the execution of right depends on the left value and the right node might be arbitrarily
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
deleted file mode 100644
index 36f9c1ca7505be6d75c2ac06bde56adb190c2d46..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryNode.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.binary;
-
-import com.oracle.truffle.api.dsl.NodeChild;
-import com.oracle.truffle.r.runtime.nodes.RNode;
-
-@NodeChild(value = "left", type = RNode.class)
-@NodeChild(value = "right", type = RNode.class)
-abstract class BinaryNode extends RNode {
-
-    protected abstract RNode getLeft();
-
-    protected abstract RNode getRight();
-
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
index 3b823312a6187ee801e7e9346a400331215b565e..4181bfc59c3db086c241621db21e736b521dd3b7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java
@@ -14,6 +14,7 @@ package com.oracle.truffle.r.nodes.binary;
 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.unary.CastComplexNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen;
@@ -25,9 +26,12 @@ import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
 import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
-public abstract class CastTypeNode extends BinaryNode {
+@TypeSystemReference(RTypes.class)
+public abstract class CastTypeNode extends RBaseNode {
 
     protected static final int NUMBER_OF_TYPES = RType.values().length;
 
@@ -63,7 +67,7 @@ public abstract class CastTypeNode extends BinaryNode {
     }
 
     public static CastTypeNode create() {
-        return CastTypeNodeGen.create(null, null);
+        return CastTypeNodeGen.create();
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java
index 6b29fde9932f27040314cd60c22695c69895e76b..7fceec433df39e63feb9c9b22ecee7b34d0a9d07 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.nodes.control.OperatorNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
-import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
@@ -194,7 +193,6 @@ public abstract class InternalNode extends OperatorNode {
         protected final int varArgIndex;
 
         @Children protected final RNode[] arguments;
-        @Children protected final CastNode[] casts;
         @Child private RBuiltinNode builtin;
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
@@ -202,15 +200,11 @@ public abstract class InternalNode extends OperatorNode {
             super(src, operator, outerSignature, outerArgs);
             this.factory = factory;
             this.builtin = factory.getConstructor().get();
-            this.casts = builtin.getCasts();
             this.arguments = new RNode[args.length];
             for (int i = 0; i < args.length; i++) {
                 arguments[i] = ((RSyntaxNode) args[i]).asRNode();
             }
             this.varArgIndex = factory.getSignature().getVarArgIndex();
-            if (varArgIndex != ArgumentsSignature.NO_VARARG) {
-                assert casts.length <= varArgIndex || casts[varArgIndex] == null : "no casts on '...' arguments to .Internals";
-            }
         }
 
         @Override
@@ -222,7 +216,7 @@ public abstract class InternalNode extends OperatorNode {
 
         @Override
         public Object execute(VirtualFrame frame) {
-            Object result = builtin.executeBuiltin(frame, prepareArgs(frame));
+            Object result = builtin.call(frame, prepareArgs(frame));
             assert result != null : "builtins cannot return 'null': " + factory.getName();
             assert !(result instanceof RConnection) : "builtins cannot return connection': " + factory.getName();
             visibility.execute(frame, factory.getVisibility());
@@ -231,7 +225,7 @@ public abstract class InternalNode extends OperatorNode {
 
         @Override
         public void voidExecute(VirtualFrame frame) {
-            builtin.executeBuiltin(frame, prepareArgs(frame));
+            builtin.call(frame, prepareArgs(frame));
         }
     }
 
@@ -250,11 +244,7 @@ public abstract class InternalNode extends OperatorNode {
         protected Object[] prepareArgs(VirtualFrame frame) {
             Object[] args = new Object[arguments.length];
             for (int i = 0; i < args.length; i++) {
-                Object value = arguments[i].execute(frame);
-                if (i < casts.length && casts[i] != null) {
-                    value = casts[i].execute(value);
-                }
-                args[i] = value;
+                args[i] = arguments[i].execute(frame);
             }
             return args;
         }
@@ -281,10 +271,6 @@ public abstract class InternalNode extends OperatorNode {
                 Object value = arguments[i].execute(frame);
                 if (i == varArgIndex) {
                     value = forcePromises(frame, (RArgsValuesAndNames) value);
-                } else {
-                    if (i < casts.length && casts[i] != null) {
-                        value = casts[i].execute(value);
-                    }
                 }
                 args[i] = value;
             }
@@ -316,11 +302,7 @@ public abstract class InternalNode extends OperatorNode {
             Object[] args = new Object[factory.getSignature().getLength()];
 
             for (int i = 0; i < args.length - 1; i++) {
-                Object value = arguments[i].execute(frame);
-                if (i < casts.length && casts[i] != null) {
-                    value = casts[i].execute(value);
-                }
-                args[i] = value;
+                args[i] = arguments[i].execute(frame);
             }
             Object[] varArgs = new Object[arguments.length - (factory.getSignature().getLength() - 1)];
             for (int i = 0; i < varArgs.length; i++) {
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 f3c4cc292ef9ea2a826c0278b5d2b3a45b1342b9..d2ed7222a44bc9a49cf9a19794cf2a6f8ca033ff 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
@@ -22,11 +22,15 @@
  */
 package com.oracle.truffle.r.nodes.builtin;
 
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.dsl.GeneratedBy;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.ErrorContext;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
@@ -45,7 +49,7 @@ import com.oracle.truffle.r.runtime.nodes.builtin.RBuiltinBaseNode;
 @TypeSystemReference(RTypes.class)
 public abstract class RBuiltinNode extends RBuiltinBaseNode implements NodeWithArgumentCasts {
 
-    public abstract Object executeBuiltin(VirtualFrame frame, Object... args);
+    public abstract Object call(VirtualFrame frame, Object... args);
 
     /**
      * Return the default values of the builtin's formal arguments. This is only valid for builtins
@@ -108,4 +112,221 @@ public abstract class RBuiltinNode extends RBuiltinBaseNode implements NodeWithA
         ErrorContext context = RError.contextForBuiltin(getRBuiltin());
         return context == null ? this : context;
     }
+
+    @Children private final CastNode[] argumentCasts;
+    @CompilationFinal(dimensions = 1) private final Class<?>[] argumentClasses;
+    private final ValueProfile castClassProfile = ValueProfile.createClassProfile();
+
+    protected RBuiltinNode(int argCount) {
+        argumentCasts = getCasts();
+        argumentClasses = new Class<?>[argCount];
+    }
+
+    protected Object castArg(Object[] args, int index) {
+        Object value;
+        if (index < argumentCasts.length && argumentCasts[index] != null) {
+            value = argumentCasts[index].execute(castClassProfile.profile(args[index]));
+        } else {
+            value = args[index];
+        }
+        Class<?> clazz = argumentClasses[index];
+        if (clazz == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            argumentClasses[index] = clazz = value.getClass();
+            return value;
+        } else if (clazz == Object.class) {
+            return value;
+        } else if (value.getClass() == clazz) {
+            if (CompilerDirectives.inInterpreter()) {
+                return value;
+            }
+            return clazz.cast(value);
+        } else {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            argumentClasses[index] = Object.class;
+            return value;
+        }
+    }
+
+    public abstract static class Arg0 extends RBuiltinNode {
+
+        public abstract Object execute(VirtualFrame frame);
+
+        protected Arg0() {
+            super(0);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame);
+        }
+    }
+
+    public abstract static class Arg1 extends RBuiltinNode {
+        public abstract Object execute(VirtualFrame frame, Object arg);
+
+        protected Arg1() {
+            super(1);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0));
+        }
+    }
+
+    public abstract static class Arg2 extends RBuiltinNode {
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2);
+
+        protected Arg2() {
+            super(2);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1));
+        }
+    }
+
+    public abstract static class Arg3 extends RBuiltinNode {
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3);
+
+        protected Arg3() {
+            super(3);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2));
+        }
+    }
+
+    public abstract static class Arg4 extends RBuiltinNode {
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4);
+
+        protected Arg4() {
+            super(4);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3));
+        }
+    }
+
+    public abstract static class Arg5 extends RBuiltinNode {
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5);
+
+        protected Arg5() {
+            super(5);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4));
+        }
+    }
+
+    public abstract static class Arg6 extends RBuiltinNode {
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6);
+
+        protected Arg6() {
+            super(6);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4), castArg(args, 5));
+        }
+    }
+
+    public abstract static class Arg7 extends RBuiltinNode {
+
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7);
+
+        protected Arg7() {
+            super(7);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4), castArg(args, 5), castArg(args, 6));
+        }
+    }
+
+    public abstract static class Arg8 extends RBuiltinNode {
+
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8);
+
+        protected Arg8() {
+            super(8);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4), castArg(args, 5), castArg(args, 6), castArg(args, 7));
+        }
+    }
+
+    public abstract static class Arg9 extends RBuiltinNode {
+
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9);
+
+        protected Arg9() {
+            super(9);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4), castArg(args, 5), castArg(args, 6), castArg(args, 7), castArg(args, 8));
+        }
+    }
+
+    public abstract static class Arg10 extends RBuiltinNode {
+
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10);
+
+        protected Arg10() {
+            super(10);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4), castArg(args, 5), castArg(args, 6), castArg(args, 7), castArg(args, 8),
+                            castArg(args, 9));
+        }
+    }
+
+    public abstract static class Arg11 extends RBuiltinNode {
+
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10,
+                        Object arg11);
+
+        protected Arg11() {
+            super(11);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4), castArg(args, 5), castArg(args, 6), castArg(args, 7), castArg(args, 8),
+                            castArg(args, 9), castArg(args, 10));
+        }
+    }
+
+    public abstract static class Arg19 extends RBuiltinNode {
+
+        public abstract Object execute(VirtualFrame frame, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10,
+                        Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19);
+
+        protected Arg19() {
+            super(19);
+        }
+
+        @Override
+        public final Object call(VirtualFrame frame, Object... args) {
+            return execute(frame, castArg(args, 0), castArg(args, 1), castArg(args, 2), castArg(args, 3), castArg(args, 4), castArg(args, 5), castArg(args, 6), castArg(args, 7), castArg(args, 8),
+                            castArg(args, 9), castArg(args, 10), castArg(args, 11), castArg(args, 12), castArg(args, 13), castArg(args, 14), castArg(args, 15), castArg(args, 16), castArg(args, 17),
+                            castArg(args, 18));
+        }
+    }
 }
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 88652dcff593da9f9dbe5f59bcddc6c084d16c8c..32eb510cc7ad64356f927f4ade21c5daef213820 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
@@ -33,8 +33,10 @@ import com.oracle.truffle.r.nodes.access.AccessArgumentNode;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.RCallNode.BuiltinCallNode;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.FastPathFactory;
+import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 
@@ -44,21 +46,31 @@ public final class RBuiltinRootNode extends RRootNode {
     @Children private final AccessArgumentNode[] args;
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-    private final RBuiltinNode builtin;
     private final RBuiltinFactory factory;
 
-    RBuiltinRootNode(RBuiltinFactory factory, RBuiltinNode builtin, FormalArguments formalArguments, FrameDescriptor frameDescriptor, FastPathFactory fastPath) {
-        super(formalArguments, frameDescriptor, fastPath);
+    RBuiltinRootNode(RBuiltinFactory factory, FrameDescriptor frameDescriptor, FastPathFactory fastPath) {
+        super(frameDescriptor, fastPath);
         this.factory = factory;
-        this.builtin = builtin;
         this.args = new AccessArgumentNode[factory.getSignature().getLength()];
     }
 
+    @Override
+    public FormalArguments getFormalArguments() {
+        initialize();
+        return call.getFormals();
+    }
+
+    @Override
+    public ArgumentsSignature getSignature() {
+        initialize();
+        return call.getFormals().getSignature();
+    }
+
     @Override
     public RootCallTarget duplicateWithNewFrameDescriptor() {
         FrameDescriptor frameDescriptor = new FrameDescriptor();
         FrameSlotChangeMonitor.initializeFunctionFrameDescriptor("builtin", frameDescriptor);
-        return Truffle.getRuntime().createCallTarget(new RBuiltinRootNode(factory, (RBuiltinNode) builtin.deepCopy(), getFormalArguments(), frameDescriptor, getFastPath()));
+        return Truffle.getRuntime().createCallTarget(new RBuiltinRootNode(factory, frameDescriptor, getFastPath()));
     }
 
     @Override
@@ -71,14 +83,7 @@ public final class RBuiltinRootNode extends RRootNode {
     public Object execute(VirtualFrame frame) {
         verifyEnclosingAssumptions(frame);
         try {
-            if (call == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                this.call = insert(new BuiltinCallNode(builtin, factory, getFormalArguments(), null, true));
-                for (int i = 0; i < args.length; i++) {
-                    args[i] = insert(AccessArgumentNode.create(i));
-                    args[i].setFormals(getFormalArguments());
-                }
-            }
+            initialize();
             Object[] arguments = new Object[args.length];
             for (int i = 0; i < args.length; i++) {
                 arguments[i] = args[i].execute(frame);
@@ -93,8 +98,26 @@ public final class RBuiltinRootNode extends RRootNode {
         }
     }
 
+    private void initialize() {
+        if (call == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            RBuiltinNode builtin = factory.getConstructor().get();
+            FormalArguments formalArguments = FormalArguments.createForBuiltin(builtin.getDefaultParameterValues(), factory.getSignature());
+            if (factory.getKind() == RBuiltinKind.INTERNAL) {
+                assert builtin.getDefaultParameterValues().length == 0 : "INTERNAL builtins do not need default values";
+                assert factory.getSignature().getVarArgCount() == 0 || factory.getSignature().getVarArgIndex() == factory.getSignature().getLength() - 1 : "only last argument can be vararg";
+            }
+            call = insert(new BuiltinCallNode(builtin, factory, formalArguments, null, true));
+            for (int i = 0; i < args.length; i++) {
+                args[i] = insert(AccessArgumentNode.create(i));
+                args[i].setFormals(formalArguments);
+            }
+        }
+    }
+
     public RBuiltinNode getBuiltinNode() {
-        return builtin;
+        initialize();
+        return call.getBuiltin();
     }
 
     @Override
@@ -119,6 +142,6 @@ public final class RBuiltinRootNode extends RRootNode {
 
     @Override
     public String getName() {
-        return "RBuiltin(" + builtin + ")";
+        return "RBuiltin(" + factory.getName() + ")";
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInvisibleBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInvisibleBuiltinNode.java
deleted file mode 100644
index 0577e23b3ad2b3a3ab42a87aaef40e0e2374005c..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RInvisibleBuiltinNode.java
+++ /dev/null
@@ -1,27 +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.nodes.builtin;
-
-public abstract class RInvisibleBuiltinNode extends RBuiltinNode {
-
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RPrecedenceBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RPrecedenceBuiltinNode.java
index aa07294e9735b4add74e3389b25aa6d05b411b47..fd3d5d3106b2e593b0756a529b7b4411566c92e7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RPrecedenceBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RPrecedenceBuiltinNode.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,7 +26,7 @@ import com.oracle.truffle.r.nodes.unary.PrecedenceNode;
 import com.oracle.truffle.r.nodes.unary.PrecedenceNodeGen;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 
-public abstract class RPrecedenceBuiltinNode extends RBuiltinNode {
+public abstract class RPrecedenceBuiltinNode extends RBuiltinNode.Arg3 {
 
     @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create();
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
index d735d29331edd27b76600587b19a57fb3b13c2b1..0e77db678e9fdab5a97ca7e600f8e50b192d17aa 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
@@ -29,7 +29,6 @@ import com.oracle.truffle.r.nodes.function.call.CallRFunctionCachedNodeGen;
 import com.oracle.truffle.r.nodes.function.call.CallRFunctionNode;
 import com.oracle.truffle.r.nodes.function.signature.VarArgsHelper;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
-import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RArguments.DispatchArgs;
@@ -187,7 +186,6 @@ public abstract class CallMatcherNode extends RBaseNode {
         @Child private CallMatcherNode next;
         @Child private CallRFunctionNode call;
         @Child private RBuiltinNode builtin;
-        @Children private final CastNode[] builtinArgumentCasts;
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
         private final RBuiltinDescriptor builtinDescriptor;
@@ -218,12 +216,10 @@ public abstract class CallMatcherNode extends RBaseNode {
             if (function.isBuiltin()) {
                 this.builtinDescriptor = function.getRBuiltin();
                 this.builtin = RBuiltinNode.inline(builtinDescriptor);
-                this.builtinArgumentCasts = builtin.getCasts();
                 this.fastPath = null;
                 this.fastPathVisibility = null;
             } else {
                 this.call = CallRFunctionNode.create(function.getTarget());
-                this.builtinArgumentCasts = null;
                 this.builtinDescriptor = null;
                 FastPathFactory fastPathFactory = root.getFastPath();
                 this.fastPath = fastPathFactory == null ? null : fastPathFactory.create();
@@ -273,8 +269,7 @@ public abstract class CallMatcherNode extends RBaseNode {
                         visibility.executeAfterCall(frame, caller);
                     }
                 } else {
-                    applyCasts(reorderedArgs);
-                    Object result = builtin.executeBuiltin(frame, reorderedArgs);
+                    Object result = builtin.call(frame, reorderedArgs);
                     visibility.execute(frame, builtinDescriptor.getVisibility());
                     return result;
                 }
@@ -283,16 +278,6 @@ public abstract class CallMatcherNode extends RBaseNode {
             }
         }
 
-        @ExplodeLoop
-        private void applyCasts(Object[] reorderedArgs) {
-            for (int i = 0; i < builtinArgumentCasts.length; i++) {
-                CastNode cast = builtinArgumentCasts[i];
-                if (cast != null) {
-                    reorderedArgs[i] = cast.execute(reorderedArgs[i]);
-                }
-            }
-        }
-
         @Override
         @ExplodeLoop
         protected void replaceMissingArguments(RFunction function, Object[] args) {
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 37ff3d56af59c962099bc4223e5b1ca7758c3972..89c214040ceda244a24290cb59deb3440901c544 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
@@ -82,7 +82,10 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor;
 
 public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNode, RSyntaxFunction {
 
-    @Child private RNode body; // typed as RNode to avoid custom instrument wrapper
+    private final FormalArguments formalArguments;
+
+    @Child private RNode body;
+
     /**
      * This exists for debugging purposes. It is set initially when the function is defined to
      * either:
@@ -135,7 +138,8 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
 
     private FunctionDefinitionNode(SourceSection src, FrameDescriptor frameDesc, SourceSection[] argSourceSections, RNode saveArguments, RSyntaxNode body, FormalArguments formals,
                     String name, PostProcessArgumentsNode argPostProcess) {
-        super(formals, frameDesc, RASTBuilder.createFunctionFastPath(body, formals.getSignature()));
+        super(frameDesc, RASTBuilder.createFunctionFastPath(body, formals.getSignature()));
+        this.formalArguments = formals;
         this.argSourceSections = argSourceSections;
         assert FrameSlotChangeMonitor.isValidFrameDescriptor(frameDesc);
         assert src != null;
@@ -149,6 +153,16 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         this.argPostProcess = argPostProcess;
     }
 
+    @Override
+    public FormalArguments getFormalArguments() {
+        return formalArguments;
+    }
+
+    @Override
+    public ArgumentsSignature getSignature() {
+        return formalArguments.getSignature();
+    }
+
     @Override
     public RootCallTarget duplicateWithNewFrameDescriptor() {
         RCodeBuilder<RSyntaxNode> builder = RContext.getASTBuilder();
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 1350b4bd2ad4649fb009afc620f639126176aef5..a2bf334242b3b14374d164e4cd87b2b71089bc7a 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
@@ -65,7 +65,6 @@ import com.oracle.truffle.r.nodes.function.call.PrepareArguments;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
-import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.runtime.Arguments;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments;
@@ -778,7 +777,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         @Child private RBuiltinNode builtin;
         @Child private PromiseCheckHelperNode varArgsPromiseHelper;
         @Children private final PromiseHelperNode[] promiseHelpers;
-        @Children private final CastNode[] casts;
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
         // not using profiles to save overhead
@@ -796,7 +794,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             this.builtin = builtin;
             this.builtinDescriptor = builtinDescriptor;
             this.explicitArgs = explicitArgs;
-            this.casts = builtin.getCasts();
             this.formals = formalArguments;
             promiseHelpers = new PromiseHelperNode[formals.getLength()];
             argEmptySeen = new boolean[formals.getLength()];
@@ -810,6 +807,14 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             return builtin.getErrorContext();
         }
 
+        public RBuiltinNode getBuiltin() {
+            return builtin;
+        }
+
+        public FormalArguments getFormals() {
+            return formals;
+        }
+
         @ExplodeLoop
         public Object[] castArguments(VirtualFrame frame, Object[] args) {
             int argCount = formals.getLength();
@@ -844,12 +849,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                             }
                             arg = promiseHelpers[i].evaluate(frame, (RPromise) arg);
                         }
-                        if (i < casts.length && casts[i] != null) {
-                            assert builtinDescriptor.evaluatesArg(i);
-                            arg = casts[i].execute(arg);
-                        }
                     } else {
-                        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();
@@ -917,7 +917,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
 
         @Override
         public Object execute(VirtualFrame frame, RFunction currentFunction, RArgsValuesAndNames orderedArguments, S3Args s3Args) {
-            Object result = builtin.executeBuiltin(frame, castArguments(frame, orderedArguments.getArguments()));
+            Object result = builtin.call(frame, castArguments(frame, orderedArguments.getArguments()));
             assert result != null : "builtins cannot return 'null': " + builtinDescriptor.getName();
             assert !(result instanceof RConnection) : "builtins cannot return connection': " + builtinDescriptor.getName();
             visibility.execute(frame, builtinDescriptor.getVisibility());
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 ff0bab5975a100e4eaeae502d20aeaf83d7ee1b1..cf9c38a6aaefb27f6cdb2b8983a7111c4c5ccb78 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
@@ -85,4 +85,8 @@ public abstract class TypeofNode extends UnaryNode {
         CompilerAsserts.neverPartOfCompilation();
         return ((RTypedValue) RRuntime.asAbstractVector(operand)).getRType();
     }
+
+    public static TypeofNode create() {
+        return TypeofNodeGen.create();
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticBuiltinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticBuiltinNode.java
index 30a73667726f4ce93ffccb7cce8b61ae19bdf4ee..b251f47a8409c50103beae9c99b8ebc40e918665 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticBuiltinNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticBuiltinNode.java
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.ops.UnaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.UnaryArithmeticFactory;
 
-public abstract class UnaryArithmeticBuiltinNode extends RBuiltinNode implements UnaryArithmeticFactory {
+public abstract class UnaryArithmeticBuiltinNode extends RBuiltinNode.Arg1 implements UnaryArithmeticFactory {
 
     @Child private BoxPrimitiveNode boxPrimitive = BoxPrimitiveNodeGen.create();
     @Child private UnaryArithmeticNode unaryNode;
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 ab41637a8301b50b454605808539fc566bd8bdb0..29484784d21defcb7b3e791c940e8b4c77ca75ad 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
@@ -49,7 +49,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
 @RBuiltin(name = "!", kind = PRIMITIVE, parameterNames = {""}, dispatch = OPS_GROUP_GENERIC, behavior = PURE)
-public abstract class UnaryNotNode extends RBuiltinNode {
+public abstract class UnaryNotNode extends RBuiltinNode.Arg1 {
 
     private final NACheck na = NACheck.create();
     private final NAProfile naProfile = NAProfile.create();