diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
index a3211b25f002f996ba8a590a1eb0d774a3d48d18..f5c37b9d496285ae269cdf0078e4ac883bd67ff2 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java
@@ -365,7 +365,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
                 newNames[i] = names.getDataAt(j);
             }
             // copying is already handled by RShareable
-            rl.setRep(RCallNode.createCall(RSyntaxNode.INTERNAL, ((RCallNode) node).getFunctionNode(), ArgumentsSignature.get(newNames), args.getArguments()));
+            rl.setRep(RCallNode.createCall(RSyntaxNode.INTERNAL, ((RCallNode) node).getFunction(), ArgumentsSignature.get(newNames), args.getArguments()));
         } else {
             throw RInternalError.shouldNotReachHere();
         }
@@ -420,21 +420,21 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
         while (call.isPromise()) {
             call = call.getParent();
         }
-        RSyntaxNode syntaxNode = call.getSyntaxNode();
-        return RDataFactory.createLanguage(syntaxNode.asRNode());
+        RSyntaxElement syntaxNode = call.getSyntaxNode();
+        return RDataFactory.createLanguage(((RSyntaxNode) syntaxNode).asRNode());
     }
 
     private static RBaseNode checkBuiltin(RBaseNode bn) {
         if (bn instanceof RBuiltinNode) {
-            RSyntaxNode sn = ((RBuiltinNode) bn).getOriginalCall();
-            if (sn == null) {
+            RSyntaxElement se = ((RBuiltinNode) bn).getOriginalCall();
+            if (se == null) {
                 /*
                  * TODO Ideally this never happens but do.call creates trees that make finding the
                  * original call impossible.
                  */
                 return null;
             } else {
-                return (RBaseNode) sn;
+                return (RBaseNode) se;
             }
         } else {
             return bn;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
index 5bb77e6214b8099938d01efdafee8e4a6b594697..8b150e7d17bcadedeeb9fdb21a9e50e1affe1e7d 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
@@ -58,6 +58,7 @@ import com.oracle.truffle.r.runtime.data.MemoryCopyTracer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 /**
@@ -152,7 +153,7 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
         }
     }
 
-    private static String getPath(RSyntaxNode node) {
+    private static String getPath(RSyntaxElement node) {
         Source source = node.getSourceSection().getSource();
         String path = RSource.getPath(source);
         return path;
@@ -187,7 +188,7 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
      * collects the stack of functions.
      */
     private final class StatementListener implements ExecutionEventListener {
-        private ArrayList<ArrayList<RSyntaxNode>> intervalStacks = new ArrayList<>();
+        private ArrayList<ArrayList<RSyntaxElement>> intervalStacks = new ArrayList<>();
         private ArrayList<RprofState.MemoryQuad> intervalMemory = new ArrayList<>();
         private volatile boolean newInterval;
 
@@ -206,8 +207,8 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
         public void onEnter(EventContext context, VirtualFrame frame) {
             if (newInterval) {
                 /* context tells here we are now, frame provides callers. */
-                final ArrayList<RSyntaxNode> stack = new ArrayList<>();
-                stack.add((RSyntaxNode) context.getInstrumentedNode());
+                final ArrayList<RSyntaxElement> stack = new ArrayList<>();
+                stack.add((RSyntaxElement) context.getInstrumentedNode());
                 collectStack(stack);
                 intervalStacks.add(stack);
                 RprofState profState = RprofState.get();
@@ -220,7 +221,7 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
         }
 
         @TruffleBoundary
-        private void collectStack(final ArrayList<RSyntaxNode> stack) {
+        private void collectStack(final ArrayList<RSyntaxElement> stack) {
             Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
 
                 @Override
@@ -230,7 +231,7 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
                         while (call.isPromise()) {
                             call = call.getParent();
                         }
-                        RSyntaxNode syntaxNode = call.getSyntaxNode();
+                        RSyntaxElement syntaxNode = call.getSyntaxNode();
                         stack.add(syntaxNode);
                     }
                     return null;
@@ -317,8 +318,8 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
                 // scan stacks to find files
                 fileMap = new HashMap<>();
                 int fileIndex = 0;
-                for (ArrayList<RSyntaxNode> intervalStack : statementListener.intervalStacks) {
-                    for (RSyntaxNode node : intervalStack) {
+                for (ArrayList<RSyntaxElement> intervalStack : statementListener.intervalStacks) {
+                    for (RSyntaxElement node : intervalStack) {
                         String path = getPath(node);
                         if (path != null && fileMap.get(path) == null) {
                             fileMap.put(path, ++fileIndex);
@@ -328,13 +329,13 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFa
                 }
             }
             int index = 0;
-            for (ArrayList<RSyntaxNode> intervalStack : statementListener.intervalStacks) {
+            for (ArrayList<RSyntaxElement> intervalStack : statementListener.intervalStacks) {
                 if (this.memoryProfiling) {
                     RprofState.MemoryQuad mq = statementListener.intervalMemory.get(index);
                     out.printf(":%d:%d:%d:%d:", mq.largeV, mq.smallV, mq.nodes, mq.copied);
                 }
-                for (RSyntaxNode node : intervalStack) {
-                    RootNode rootNode = node.asRNode().getRootNode();
+                for (RSyntaxElement node : intervalStack) {
+                    RootNode rootNode = ((RSyntaxNode) node).asRNode().getRootNode();
                     if (rootNode instanceof FunctionDefinitionNode) {
                         String name = rootNode.getName();
                         if (this.lineProfiling) {
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 932b06f368fd4e81dd7afcadafe45fce41c5bf26..f53488c08b4fc3a18344afe792544302487d5ed8 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
@@ -41,13 +41,11 @@ public abstract class CRC64 extends RBuiltinNode {
 
     @Override
     protected void createCasts(CastBuilder casts) {
-        casts.arg("x").conf(x -> x.mustNotBeMissing(RError.SHOW_CALLER2, Message.ARGUMENTS_PASSED_INTERNAL_0_1, getRBuiltin().name())).mustNotBeNull(RError.NO_CALLER,
-                        Message.INPUT_MUST_BE_STRING).mustBe(stringValue(), RError.NO_CALLER, Message.INPUT_MUST_BE_STRING);
+        casts.arg("x").mustNotBeNull(RError.NO_CALLER, Message.INPUT_MUST_BE_STRING).mustBe(stringValue(), RError.NO_CALLER, Message.INPUT_MUST_BE_STRING);
     }
 
     @Specialization
     protected RAbstractStringVector crc64(RAbstractStringVector x) {
         return RDataFactory.createStringVector(Crc64.crc(x));
     }
-
 }
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 ad202b972214cd5b500b37986073d7e08fe209d1..a25872ef517840128479cdda2e2a640b2b183c2c 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
@@ -347,7 +347,7 @@ public class FrameFunctions {
             sig = ArgumentsSignature.get(names.toArray(new String[names.size()]));
             RSyntaxNode[] newArgs = nodes.toArray(new RSyntaxNode[nodes.size()]);
 
-            RSyntaxNode modCallNode = RASTUtils.createCall(callNode.getFunctionNode(), false, sig, newArgs);
+            RSyntaxNode modCallNode = RASTUtils.createCall(callNode.getFunction(), false, sig, newArgs);
             return RDataFactory.createLanguage(modCallNode.asRNode());
         }
 
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 c77b2e404f7fe46f7c3dd1f9d1deb1d6e8d0369c..4a50c81280e7b7eed1a0050dcecf1a5a3eb06acb 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
@@ -22,116 +22,24 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.api.nodes.NodeCost.NONE;
 import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.dsl.TypeSystemReference;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.RASTUtils;
-import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.nodes.function.RCallNode;
-import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RMissing;
-import com.oracle.truffle.r.runtime.data.RPromise;
-import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode;
-import com.oracle.truffle.r.runtime.nodes.RNode;
 
 /**
- * The {@code .Internal} builtin. In {@code .Internal(func(args))} we have an AST where the
- * RCallNode.Uninitialized and the function child should be a {@link ReadVariableNode} node with
- * symbol {@code func}. We want to rewrite the AST as if the {@code func} had been called directly.
- * However, we must do this in a non-destructive way otherwise deparsing and serialization will
- * fail.
- *
- * A note on {@link RInstrumentableNode}. Since both the {@code .Internal} and the argument are
- * {@link RCallNode}s both may have been wrapped. The call to {@link RASTUtils#unwrap} will go
- * through any {@code RNodeWrapper} and the rewrite will remove one level of wrapping. However the
- * parent of the the {@code .Internal}, which will be an {@code RNodeWrapper}, will remain so any
- * instrumentation at that level will remain in place.
+ * .Internal is resolved during AST creation, so this builtin is only a dummy to make the name
+ * visible.
  */
-@TypeSystemReference(EmptyTypeSystemFlatLayout.class)
-@NodeInfo(cost = NONE)
 @RBuiltin(name = ".Internal", visibility = CUSTOM, kind = PRIMITIVE, parameterNames = {"call"}, nonEvalArgs = 0, behavior = COMPLEX)
 public abstract class Internal extends RBuiltinNode {
 
-    private final BranchProfile errorProfile = BranchProfile.create();
-
-    @Child private RNode builtinCallNode;
-
     @Specialization
-    protected Object doInternal(@SuppressWarnings("unused") RMissing x) {
-        errorProfile.enter();
-        throw RError.error(this, RError.Message.ARGUMENTS_PASSED_0_1, getRBuiltin().name());
+    protected Object doInternal(@SuppressWarnings("unused") Object x) {
+        throw RInternalError.unimplemented();
     }
-
-    @Specialization
-    protected Object doInternal(VirtualFrame frame, RPromise x) {
-        if (builtinCallNode == null) {
-            RNode call = (RNode) x.getRep();
-            RNode operand = (RNode) RASTUtils.unwrap(call);
-
-            if (!(operand instanceof RCallNode)) {
-                errorProfile.enter();
-                throw RError.error(this, RError.Message.INVALID_INTERNAL);
-            }
-
-            RCallNode callNode = (RCallNode) operand;
-            RNode func = callNode.getFunctionNode();
-            String name = ((ReadVariableNode) func).getIdentifier();
-            RFunction function = RContext.lookupBuiltin(name);
-            if (function == null || function.isBuiltin() && function.getRBuiltin().getKind() != RBuiltinKind.INTERNAL) {
-                errorProfile.enter();
-                if (function == null && notImplemented(name)) {
-                    throw RInternalError.unimplemented(".Internal " + name);
-                }
-                throw RError.error(this, RError.Message.NO_SUCH_INTERNAL, name);
-            }
-
-            // .Internal function is validated
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            builtinCallNode = insert(RCallNode.createInternalCall(callNode, function));
-        }
-        return builtinCallNode.execute(frame);
-    }
-
-    private static boolean notImplemented(String name) {
-        for (String internal : NOT_IMPLEMENTED) {
-            if (internal.equals(name)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // TODO check this; it is out of date
-    private static final String[] NOT_IMPLEMENTED = new String[]{
-                    ".addTryHandlers", "interruptsSuspended", "restart", "backsolve", "max.col", "row", "all.names", "comment", "`comment<-`", "list2env", "tcrossprod", "lbeta",
-                    "beta", "lchoose", "choose", "dchisq", "pchisq", "qchisq", "dexp", "pexp", "qexp", "dgeom", "pgeom", "qgeom", "dpois", "ppois", "qpois", "dt", "pt", "qt", "dsignrank",
-                    "psignrank", "qsignrank", "besselJ", "besselY", "psigamma", "dbeta", "pbeta", "qbeta", "dbinom", "pbinom", "qbinom", "dcauchy", "pcauchy", "qcauchy", "df", "pf", "qf", "dgamma",
-                    "pgamma", "qgamma", "dlnorm", "plnorm", "qlnorm", "dlogis", "plogis", "qlogis", "dnbinom", "pnbinom", "qnbinom", "dnorm", "pnorm", "qnorm", "dunif", "punif", "qunif", "dweibull",
-                    "pweibull", "qweibull", "dnchisq", "pnchisq", "qnchisq", "dnt", "pnt", "qnt", "dwilcox", "pwilcox", "qwilcox", "besselI", "besselK", "dnbinom_mu", "pnbinom_mu", "qnbinom_mu",
-                    "dhyper", "phyper", "qhyper", "dnbeta", "pnbeta", "qnbeta", "dnf", "pnf", "qnf", "dtukey", "ptukey", "qtukey", "rchisq", "rexp", "rgeom", "rpois", "rt", "rsignrank", "rbeta",
-                    "rbinom", "rcauchy", "rf", "rgamma", "rlnorm", "rlogis", "rnbinom", "rnbinom_mu", "rnchisq", "rnorm", "runif", "rweibull", "rwilcox", "rhyper", "sample2", "format.info",
-                    "grepRaw", "regexec", "adist", "aregexec", "chartr", "intToBits", "rawToBits", "packBits", "intToUtf8", "strtrim", "eapply", "machine", "save",
-                    "saveToConn", "dput", "dump", "prmatrix", "gcinfo", "gctorture", "gctorture2", "memory.profile", "recordGraphics", "sys.calls", "sys.on.exit", "rank", "builtins", "bodyCode",
-                    "rapply", "islistfactor", "inspect", "mem.limits", "merge", "capabilitiesX11", "Cstack_info", "file.show", "file.choose", "polyroot", "mkCode", "bcClose", "is.builtin.internal",
-                    "disassemble", "bcVersion", "load.from.file", "save.to.file", "growconst", "putconst", "getconst", "enableJIT", "setNumMathThreads", "setMaxNumMathThreads", "isatty",
-                    "isIncomplete", "pipe", "fifo", "bzfile", "xzfile", "unz", "truncate", "rawConnection", "rawConnectionValue", "sockSelect", "gzcon", "memCompress", "memDecompress", "mkUnbound",
-                    "env.profile", "setTimeLimit", "setSessionTimeLimit", "icuSetCollate", "lazyLoadDBflush", "findInterval", "pretty", "crc64", "rowsum_matrix", "rowsum_df", "setS4Object",
-                    "traceOnOff", "La_qr_cmplx", "La_rs_cmplx", "La_rg_cmplx", "La_rs", "La_rs_cmplx", "La_dlange", "La_dgecon", "La_dtrcon", "La_zgecon", "La_ztrcon", "La_solve_cmplx",
-                    "La_chol2inv", "qr_qy_real", "qr_coef_cmplx", "qr_qy_cmpl", "La_svd", "La_svd_cmplx"};
-
 }
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 e16383358909389c8e6b79aeecaebae583fc0358..0b7624082455fb742d7d5aba3718958da56b3113 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
@@ -77,9 +77,9 @@ public class ContextSystemFunctionFactory extends SystemFunctionFactory {
         }
 
         @Specialization
-        protected Object systemFunction(VirtualFrame frame, RAbstractStringVector args, RAbstractStringVector env, boolean intern) {
+        protected Object systemFunction(RAbstractStringVector args, RAbstractStringVector env, boolean intern) {
             initContextRscriptNode();
-            Object result = contextRscriptNode.executeBuiltin(frame, args, env, intern);
+            Object result = contextRscriptNode.execute(args, env, intern);
             return result;
         }
     }
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 dd68c15f3a66753ccf27bed53273331db337bcf7..aa78158d736e78f0f48b1a16f99e900caaf71ee0 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
@@ -22,7 +22,13 @@
  */
 package com.oracle.truffle.r.nodes.builtin.fastr;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.equalTo;
+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.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.OFF;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
@@ -256,6 +262,9 @@ 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 Object execute(RAbstractStringVector args, RAbstractStringVector env, boolean intern);
+
         @Override
         public Object[] getDefaultParameterValues() {
             return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE};
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java
index 8a1e544b5231732db03711ea6fa77808327c80a9..271946acb29ae950b84d53faa0b7736c23e048e8 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.ReadVariadicComponentNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
+import com.oracle.truffle.r.nodes.builtin.InternalNode;
 import com.oracle.truffle.r.nodes.control.BlockNode;
 import com.oracle.truffle.r.nodes.control.BreakNode;
 import com.oracle.truffle.r.nodes.control.ForNode;
@@ -139,6 +140,8 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> {
                     return new BlockNode(source, lhsLookup, args.stream().map(n -> n.value.asRNode()).toArray(RNode[]::new));
                 case "missing":
                     return new MissingNode(source, lhsLookup, createSignature(args), args.stream().map(a -> a.value).toArray(RSyntaxElement[]::new));
+                case ".Internal":
+                    return InternalNode.create(source, lhsLookup, createSignature(args), args.stream().map(a -> a.value).toArray(RSyntaxNode[]::new));
             }
         }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
index 110a168f5d2460dc4e56ec5c8537ff20118363a6..21a4e1293a6cecd42faaa778194bc48c1d43944a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java
@@ -53,6 +53,7 @@ import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
@@ -96,7 +97,7 @@ public class RASTUtils {
     }
 
     @TruffleBoundary
-    public static RSyntaxNode getOriginalCall(Node node) {
+    public static RSyntaxElement getOriginalCall(Node node) {
         Node p = node.getParent();
         while (p != null) {
             if (p instanceof RBuiltinNode) {
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
new file mode 100644
index 0000000000000000000000000000000000000000..48ff3250322af8cda13932b504247456e30646be
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
+import com.oracle.truffle.api.source.SourceSection;
+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;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
+import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
+import com.oracle.truffle.r.runtime.conn.RConnection;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
+import com.oracle.truffle.r.runtime.data.REmpty;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.nodes.RNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+
+/**
+ * This node is used during AST creation to represent a .Internal call. Upon the first execution, it
+ * will examine its arguments, raising errors if necessary, and rewrite itself to a version that
+ * fits the arguments. The main difference in how arguments are passed is in whether varargs are
+ * introduced or forwarded by the call to the .Internal.
+ */
+public abstract class InternalNode extends OperatorNode {
+
+    protected final ArgumentsSignature outerSignature;
+    protected final RSyntaxNode[] outerArgs;
+
+    public InternalNode(SourceSection src, RSyntaxLookup operator, ArgumentsSignature outerSignature, RSyntaxNode[] outerArgs) {
+        super(src, operator);
+        this.outerSignature = outerSignature;
+        this.outerArgs = outerArgs;
+    }
+
+    public static InternalNode create(SourceSection src, RSyntaxLookup operator, ArgumentsSignature outerSignature, RSyntaxNode[] outerArgs) {
+        return new InternalUninitializedNode(src, operator, outerSignature, outerArgs);
+    }
+
+    /**
+     * Represents an uninitialized .Internal call, executing will replace it with a more specific
+     * implementation.
+     */
+    private static final class InternalUninitializedNode extends InternalNode {
+
+        InternalUninitializedNode(SourceSection src, RSyntaxLookup operator, ArgumentsSignature outerSignature, RSyntaxNode[] outerArgs) {
+            super(src, operator, outerSignature, outerArgs);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            if (outerArgs.length != 1) {
+                throw RError.error(RError.SHOW_CALLER, Message.ARGUMENTS_PASSED, outerArgs.length, ".Internal", 1);
+            }
+            if (!(outerArgs[0] instanceof RSyntaxCall)) {
+                throw RError.error(RError.SHOW_CALLER, Message.INVALID_ARG, ".Internal()");
+            }
+
+            RSyntaxCall call = (RSyntaxCall) outerArgs[0];
+            RSyntaxElement lhs = call.getSyntaxLHS();
+
+            // extract the builtin name
+            String name = null;
+            if (lhs instanceof RSyntaxLookup) {
+                name = ((RSyntaxLookup) lhs).getIdentifier();
+            } else if (lhs instanceof RSyntaxConstant) {
+                Object constant = ((RSyntaxConstant) lhs).getValue();
+                if (constant instanceof String) {
+                    name = (String) constant;
+                } else if (constant instanceof RAbstractStringVector) {
+                    RAbstractStringVector stringVector = (RAbstractStringVector) constant;
+                    if (stringVector.getLength() == 1) {
+                        name = stringVector.getDataAt(0);
+                    }
+                }
+            }
+            if (name == null) {
+                throw RError.error(RError.SHOW_CALLER, Message.INVALID_ARG, ".Internal()");
+            }
+
+            RFunction function = RContext.lookupBuiltin(name);
+            if (function == null || function.isBuiltin() && function.getRBuiltin().getKind() != RBuiltinKind.INTERNAL) {
+                // determine whether we're supposed to implement this builtin
+                if (function == null && NOT_IMPLEMENTED.contains(name)) {
+                    throw RInternalError.unimplemented(".Internal " + name);
+                }
+                throw RError.error(RError.SHOW_CALLER, RError.Message.NO_SUCH_INTERNAL, name);
+            }
+
+            RBuiltinFactory factory = (RBuiltinFactory) function.getRBuiltin();
+            RSyntaxElement[] callArgs = call.getSyntaxArguments();
+
+            // verify the number of arguments
+            if (factory.getSignature().getVarArgCount() == 0) {
+                if (callArgs.length != factory.getSignature().getLength()) {
+                    throw RError.error(RError.SHOW_CALLER, Message.ARGUMENTS_PASSED, callArgs.length, ".Internal(" + name + ")", factory.getSignature().getLength());
+                }
+                for (int i = 0; i < callArgs.length; i++) {
+                    if (callArgs[i] instanceof RSyntaxConstant && ((RSyntaxConstant) callArgs[i]).getValue() == REmpty.instance) {
+                        throw RError.error(RError.SHOW_CALLER, Message.ARGUMENT_EMPTY, i + 1);
+                    }
+                }
+            }
+            // look for "..." argument and verify that only one "..." is given (FastR restriction)
+            int varArgForward = ArgumentsSignature.NO_VARARG;
+            for (int i = 0; i < callArgs.length; i++) {
+                RSyntaxElement arg = callArgs[i];
+                if (arg instanceof RSyntaxLookup && ((RSyntaxLookup) arg).getIdentifier().equals(ArgumentsSignature.VARARG_NAME)) {
+                    RInternalError.guarantee(varArgForward == ArgumentsSignature.NO_VARARG, "more than one '...' in .Internal arguments is not supported");
+                    varArgForward = i;
+                }
+            }
+            int varArgIndex = factory.getSignature().getVarArgIndex();
+            if (varArgForward == varArgIndex) {
+                if (varArgIndex == ArgumentsSignature.NO_VARARG) {
+                    return replace(new InternalCallDefaultNode(getLazySourceSection(), operator, outerSignature, outerArgs, factory, callArgs)).execute(frame);
+                } else {
+                    return replace(new InternalCallVarArgForwardNode(getLazySourceSection(), operator, outerSignature, outerArgs, factory, callArgs)).execute(frame);
+                }
+            } else if (varArgForward == ArgumentsSignature.NO_VARARG) {
+                return replace(new InternalCallWrapNode(getLazySourceSection(), operator, outerSignature, outerArgs, factory, callArgs)).execute(frame);
+            } else {
+                /*
+                 * So far, refusing to handle .Internal calls that require complex argument
+                 * rematching seems reasonable.
+                 */
+                throw RInternalError.shouldNotReachHere("complex argument matching in .Internal");
+            }
+        }
+    }
+
+    /**
+     * Base class for all actual implementations of .Internal, handles everything but preparing the
+     * argument array.
+     */
+    private abstract static class InternalCallNode extends InternalNode {
+
+        protected final RBuiltinFactory factory;
+        protected final int varArgIndex;
+
+        @Children protected final RNode[] arguments;
+        @Children protected final CastNode[] casts;
+        @Child private RBuiltinNode builtin;
+        @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+
+        InternalCallNode(SourceSection src, RSyntaxLookup operator, ArgumentsSignature outerSignature, RSyntaxNode[] outerArgs, RBuiltinFactory factory, RSyntaxElement[] args) {
+            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";
+            }
+        }
+
+        protected abstract Object[] prepareArgs(VirtualFrame frame);
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object result = builtin.executeBuiltin(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());
+            return result;
+        }
+
+        @Override
+        public void voidExecute(VirtualFrame frame) {
+            builtin.executeBuiltin(frame, prepareArgs(frame));
+        }
+    }
+
+    /**
+     * Handling the case where there are no varargs.
+     */
+    private static final class InternalCallDefaultNode extends InternalCallNode {
+
+        InternalCallDefaultNode(SourceSection src, RSyntaxLookup operator, ArgumentsSignature outerSignature, RSyntaxNode[] outerArgs, RBuiltinFactory factory, RSyntaxElement[] args) {
+            super(src, operator, outerSignature, outerArgs, factory, args);
+            assert args.length == factory.getSignature().getLength();
+        }
+
+        @Override
+        @ExplodeLoop
+        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;
+            }
+            return args;
+        }
+    }
+
+    /**
+     * Handling the case where there is a single vararg parameter that is forwarded to the builtin.
+     * Any promises in the vararg need to be forced.
+     */
+    private static final class InternalCallVarArgForwardNode extends InternalCallNode {
+
+        @Child private PromiseCheckHelperNode promiseHelper = new PromiseCheckHelperNode();
+
+        InternalCallVarArgForwardNode(SourceSection src, RSyntaxLookup operator, ArgumentsSignature outerSignature, RSyntaxNode[] outerArgs, RBuiltinFactory factory, RSyntaxElement[] args) {
+            super(src, operator, outerSignature, outerArgs, factory, args);
+            assert args.length == factory.getSignature().getLength();
+        }
+
+        @Override
+        @ExplodeLoop
+        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 == varArgIndex) {
+                    value = forcePromises(frame, (RArgsValuesAndNames) value);
+                } else {
+                    if (i < casts.length && casts[i] != null) {
+                        value = casts[i].execute(value);
+                    }
+                }
+                args[i] = value;
+            }
+            return args;
+        }
+
+        private RArgsValuesAndNames forcePromises(VirtualFrame frame, RArgsValuesAndNames varArgs) {
+            Object[] array = new Object[varArgs.getLength()];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = promiseHelper.checkEvaluate(frame, varArgs.getArgument(i));
+            }
+            return new RArgsValuesAndNames(array, varArgs.getSignature());
+        }
+    }
+
+    /**
+     * Handles the case where the .Internal call specifies multiple arguments that need to be
+     * wrapped in a vararg.
+     */
+    private static final class InternalCallWrapNode extends InternalCallNode {
+
+        InternalCallWrapNode(SourceSection src, RSyntaxLookup operator, ArgumentsSignature outerSignature, RSyntaxNode[] outerArgs, RBuiltinFactory factory, RSyntaxElement[] args) {
+            super(src, operator, outerSignature, outerArgs, factory, args);
+        }
+
+        @Override
+        @ExplodeLoop
+        protected Object[] prepareArgs(VirtualFrame frame) {
+            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;
+            }
+            Object[] varArgs = new Object[arguments.length - (factory.getSignature().getLength() - 1)];
+            for (int i = 0; i < varArgs.length; i++) {
+                varArgs[i] = arguments[args.length - 1 + i].execute(frame);
+            }
+            args[args.length - 1] = new RArgsValuesAndNames(varArgs, ArgumentsSignature.empty(varArgs.length));
+            return args;
+        }
+    }
+
+    @Override
+    public RSyntaxNode[] getSyntaxArguments() {
+        return outerArgs;
+    }
+
+    @Override
+    public ArgumentsSignature getSyntaxSignature() {
+        return outerSignature;
+    }
+
+    /*
+     * This is a list of .Internal functions that should be available but may not be implemented
+     * yet. When an unknown .Internal is encountered, this list is queried to see whether it's a
+     * non-existing or an unimplemented builtin. For builtins that are implemented, it makes no
+     * difference if they are in the list or not.
+     *
+     * Some builtins, e.g., the distribution functions, are in this list because GNUR lists them as
+     * .Internal although they are never used in this way. Therefore, this list is not an accurate
+     * listing of missing builtins.
+     */
+    private static final List<String> NOT_IMPLEMENTED = Arrays.asList(
+                    ".addTryHandlers", "interruptsSuspended", "restart", "backsolve", "max.col", "comment", "`comment<-`", "list2env", "tcrossprod",
+                    "lbeta", "beta", "lchoose", "dchisq", "pchisq", "qchisq", "dexp", "pexp", "qexp", "dgeom", "pgeom", "qgeom", "dpois", "ppois", "qpois", "dt", "pt", "qt", "dsignrank", "psignrank",
+                    "qsignrank", "besselJ", "besselY", "psigamma", "dbeta", "pbeta", "qbeta", "dbinom", "pbinom", "qbinom", "dcauchy", "pcauchy", "qcauchy", "df", "pf", "qf", "dgamma", "pgamma",
+                    "qgamma", "dlnorm", "plnorm", "qlnorm", "dlogis", "plogis", "qlogis", "dnbinom", "pnbinom", "qnbinom", "dnorm", "pnorm", "qnorm", "dunif", "punif", "qunif", "dweibull", "pweibull",
+                    "qweibull", "dnchisq", "pnchisq", "qnchisq", "dnt", "pnt", "qnt", "dwilcox", "pwilcox", "qwilcox", "besselI", "besselK", "dnbinom_mu", "pnbinom_mu", "qnbinom_mu", "dhyper",
+                    "phyper", "qhyper", "dnbeta", "pnbeta", "qnbeta", "dnf", "pnf", "qnf", "dtukey", "ptukey", "qtukey", "rchisq", "rexp", "rgeom", "rpois", "rt", "rsignrank", "rbeta", "rbinom",
+                    "rcauchy", "rf", "rgamma", "rlnorm", "rlogis", "rnbinom", "rnbinom_mu", "rnchisq", "rnorm", "runif", "rweibull", "rwilcox", "rhyper",
+                    "format.info", "grepRaw", "regexec", "adist", "aregexec", "chartr", "packBits", "strtrim", "eapply", "machine", "save", "dump", "prmatrix", "gcinfo", "gctorture", "gctorture2",
+                    "memory.profile", "recordGraphics", "sys.on.exit", "builtins", "bodyCode", "rapply", "inspect",
+                    "mem.limits", "capabilitiesX11", "Cstack_info", "file.choose", "polyroot", "mkCode", "bcClose", "is.builtin.internal", "disassemble", "bcVersion", "load.from.file", "save.to.file",
+                    "growconst", "putconst", "getconst", "setNumMathThreads", "setMaxNumMathThreads", "isatty", "isIncomplete", "pipe", "fifo", "unz", "truncate", "rawConnection",
+                    "rawConnectionValue", "sockSelect", "gzcon", "memCompress", "memDecompress", "mkUnbound", "env.profile", "setSessionTimeLimit", "icuSetCollate", "findInterval", "rowsum_df",
+                    "La_qr_cmplx", "La_rs_cmplx", "La_rg_cmplx", "La_rs_cmplx", "La_dlange", "La_dgecon", "La_dtrcon", "La_zgecon", "La_ztrcon", "La_solve_cmplx", "La_chol2inv", "qr_qy_real",
+                    "qr_coef_cmplx", "qr_qy_cmpl", "La_svd", "La_svd_cmplx");
+}
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 46e7f64a39a1f501cf2a7e2e74527e7c3e8e7948..e5ae547f462f1e4142267a508b646c9e3f61704d 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
@@ -42,7 +42,9 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 
 @TypeSystemReference(RTypes.class)
 public abstract class RBuiltinNode extends RBaseNode {
@@ -74,7 +76,10 @@ public abstract class RBuiltinNode extends RBaseNode {
 
         RBuiltinNode node = builtin.getConstructor().get();
         FormalArguments formals = FormalArguments.createForBuiltin(node.getDefaultParameterValues(), builtin.getSignature());
-        assert builtin.getKind() != RBuiltinKind.INTERNAL || node.getDefaultParameterValues().length == 0 : "INTERNAL builtins do not need default values";
+        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);
@@ -107,12 +112,21 @@ public abstract class RBuiltinNode extends RBaseNode {
      * {@code do.call("func", )} have a {@link RBuiltinRootNode} as a parent, which carries no
      * context about the original call, so we return {@code null}.
      */
-    public RSyntaxNode getOriginalCall() {
+    public RSyntaxElement getOriginalCall() {
         Node p = getParent();
-        if (p instanceof RBuiltinRootNode) {
-            return null;
-        } else {
-            return ((RBaseNode) getParent()).asRSyntaxNode();
+        while (true) {
+            if (p == null) {
+                return null;
+            }
+            if (p instanceof RSyntaxCall) {
+                RSyntaxCall call = (RSyntaxCall) p;
+                if (call.getSyntaxArguments().length > 0 && call.getSyntaxLHS() instanceof RSyntaxLookup && ((RSyntaxLookup) call.getSyntaxLHS()).getIdentifier().equals(".Internal")) {
+                    // unwrap .Internal calls
+                    return call.getSyntaxArguments()[0];
+                }
+                return call;
+            }
+            p = p.getParent();
         }
     }
 
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 e034cfa67da52aab6d8a18ab88da0b95344e6a95..b137ce93957a49ff12bbb77f5edd43164f3ef873 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
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 
 public abstract class CallMatcherNode extends RBaseNode {
 
@@ -238,7 +238,7 @@ public abstract class CallMatcherNode extends RBaseNode {
                 if (call != null) {
                     RCaller parent = RArguments.getCall(frame).getParent();
                     String genFunctionName = functionName == null ? function.getName() : functionName;
-                    Supplier<RSyntaxNode> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature);
+                    Supplier<RSyntaxElement> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature);
                     RCaller caller = genFunctionName == null ? RCaller.createInvalid(frame, parent) : RCaller.create(frame, parent, argsSupplier);
                     try {
                         return call.execute(frame, cachedFunction, caller, null, reorderedArgs, matchedArgs.getSignature(), cachedFunction.getEnclosingFrame(), dispatchArgs);
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 e2019c4c78506fca390f3b711385e08ee8b1d999..85c1172c4eaf3b0f99c93907ff20423516864768 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
@@ -72,9 +72,13 @@ import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.env.frame.RFrameSlot;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor;
 
 public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNode, RSyntaxFunction {
 
@@ -184,41 +188,49 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
     }
 
     private boolean needsAnyBuiltinSplitting() {
-        NodeCountFilter findAlwaysSplitInternal = node -> {
-            if (node instanceof RCallNode) {
-                RCallNode internalCall = (RCallNode) node;
-
-                if (internalCall.getFunctionNode() instanceof ReadVariableNode) {
-                    ReadVariableNode readInternal = (ReadVariableNode) internalCall.getFunctionNode();
-
+        RSyntaxVisitor<Boolean> visitor = new RSyntaxVisitor<Boolean>() {
+
+            @Override
+            protected Boolean visit(RSyntaxCall element) {
+                RSyntaxElement lhs = element.getSyntaxLHS();
+                RSyntaxElement[] arguments = element.getSyntaxArguments();
+                if (lhs instanceof RSyntaxLookup) {
+                    String function = ((RSyntaxLookup) lhs).getIdentifier();
                     /*
                      * TODO This is a hack to make sapply split lapply. We need to find better ways
                      * to do this. If a function uses lapply anywhere as name then it gets split.
                      * This could get exploited.
                      */
-                    RBuiltinDescriptor directBuiltin = RContext.lookupBuiltinDescriptor(readInternal.getIdentifier());
+                    RBuiltinDescriptor directBuiltin = RContext.lookupBuiltinDescriptor(function);
                     if (directBuiltin != null && directBuiltin.isSplitCaller()) {
                         return true;
                     }
 
-                    if (readInternal.getIdentifier().equals(".Internal")) {
-                        Node internalFunctionArgument = RASTUtils.unwrap(internalCall.getArguments().getArguments()[0]);
-                        if (internalFunctionArgument instanceof RCallNode) {
-                            RCallNode innerCall = (RCallNode) internalFunctionArgument;
-                            if (innerCall.getFunctionNode() instanceof ReadVariableNode) {
-                                ReadVariableNode readInnerCall = (ReadVariableNode) innerCall.getFunctionNode();
-                                RBuiltinDescriptor builtin = RContext.lookupBuiltinDescriptor(readInnerCall.getIdentifier());
-                                if (builtin != null && builtin.isSplitCaller()) {
-                                    return true;
-                                }
-                            }
-                        }
+                }
+                for (RSyntaxElement arg : arguments) {
+                    if (arg != null && accept(arg)) {
+                        return true;
                     }
                 }
+                return false;
+            }
+
+            @Override
+            protected Boolean visit(RSyntaxConstant element) {
+                return false;
+            }
+
+            @Override
+            protected Boolean visit(RSyntaxLookup element) {
+                return false;
+            }
+
+            @Override
+            protected Boolean visit(RSyntaxFunction element) {
+                return false;
             }
-            return false;
         };
-        return NodeUtil.countNodes(this, findAlwaysSplitInternal) > 0;
+        return visitor.accept(getSyntaxBody());
     }
 
     @Override
@@ -258,6 +270,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
             throw e;
         } catch (RError e) {
             CompilerDirectives.transferToInterpreter();
+            SetVisibilityNode.executeSlowPath(frame, false);
             throw e;
         } catch (DebugExitException | JumpToTopLevelException | ExitException | ThreadDeath e) {
             /*
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNode.java
index 003cbce289049f7d09f3f347ddee6f2b5ad00062..ca010cb5525591933fbb4e5edf5512401033cdf7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallBaseNode.java
@@ -22,47 +22,13 @@
  */
 package com.oracle.truffle.r.nodes.function;
 
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrumentation.Instrumentable;
-import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RTypes;
 import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
-final class ForcePromiseNode extends RNode {
-
-    @Child private RNode valueNode;
-    @Child private PromiseHelperNode promiseHelper;
-    private final BranchProfile nonPromiseProfile = BranchProfile.create();
-
-    ForcePromiseNode(RNode valueNode) {
-        this.valueNode = valueNode;
-    }
-
-    public RNode getValueNode() {
-
-        return valueNode;
-    }
-
-    @Override
-    public Object execute(VirtualFrame frame) {
-        Object value = valueNode.execute(frame);
-        if (value instanceof RPromise) {
-            if (promiseHelper == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                promiseHelper = insert(new PromiseHelperNode());
-            }
-            return promiseHelper.evaluate(frame, (RPromise) value);
-        } else {
-            nonPromiseProfile.enter();
-            return value;
-        }
-    }
-}
-
 @TypeSystemReference(RTypes.class)
 @Instrumentable(factory = com.oracle.truffle.r.nodes.function.RCallBaseNodeWrapperFactory.class)
 public abstract class RCallBaseNode extends RNode implements RInstrumentableNode {
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 426f67c5df151dbaff46664de337831a1fc623b3..d2e30dd9e8bdbe712eeb9a886affff2551e83603 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
@@ -89,6 +89,7 @@ import com.oracle.truffle.r.runtime.builtins.FastPathFactory;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
 import com.oracle.truffle.r.runtime.conn.RConnection;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.REmpty;
@@ -108,7 +109,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 @TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 @NodeInfo(cost = NodeCost.NONE)
-@NodeChild(value = "function", type = ForcePromiseNode.class)
+@NodeChild(value = "function", type = RNode.class)
 public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RSyntaxCall {
 
     // currently cannot be RSourceSectionNode because of TruffleDSL restrictions
@@ -132,7 +133,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         return sourceSection;
     }
 
-    protected abstract ForcePromiseNode getFunction();
+    public abstract RNode getFunction();
 
     private final RSyntaxNode[] arguments;
     private final int[] varArgIndexes;
@@ -256,7 +257,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
     }
 
     protected RNode createDispatchArgument(int index) {
-        return new ForcePromiseNode(RASTUtils.cloneNode(arguments[index].asRNode()));
+        return RContext.getASTBuilder().process(arguments[index]).asRNode();
     }
 
     /**
@@ -530,15 +531,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         throw RError.error(RError.SHOW_CALLER, RError.Message.APPLY_NON_FUNCTION);
     }
 
-    public RNode getFunctionNode() {
-        if (getFunction() != null) {
-            // Only the very 1. RootCallNode on the top level contains the one-and-only function
-            // node
-            return getFunction().getValueNode();
-        }
-        return getParentCallNode().getFunctionNode();
-    }
-
     public CallArgumentsNode createArguments(FrameSlot tempFrameSlot, boolean modeChange, boolean modeChangeAppliesToAll) {
         RNode[] args = new RNode[arguments.length];
         for (int i = 0; i < arguments.length; i++) {
@@ -615,7 +607,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
      * {@code src == RSyntaxNode.EAGER_DEPARSE} we force a deparse.
      */
     public static RCallNode createCall(SourceSection src, RNode function, ArgumentsSignature signature, RSyntaxNode... arguments) {
-        return RCallNodeGen.create(src, arguments, signature, new ForcePromiseNode(function));
+        return RCallNodeGen.create(src, arguments, signature, function);
     }
 
     public static RCallNode createExplicitCall(Object explicitArgsIdentifier) {
@@ -630,14 +622,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         return null;
     }
 
-    private RCallNode getParentCallNode() {
-        RNode parent = (RNode) unwrapParent();
-        if (!(parent instanceof RCallNode)) {
-            throw RInternalError.shouldNotReachHere();
-        }
-        return (RCallNode) parent;
-    }
-
     static boolean needsSplitting(RootCallTarget target) {
         RRootNode root = (RRootNode) target.getRootNode();
         return root.containsDispatch() || root.needsSplitting();
@@ -994,8 +978,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
 
     @Override
     public RSyntaxElement getSyntaxLHS() {
-        ForcePromiseNode func = getFunction();
-        return func == null || func.getValueNode() == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : getFunctionNode().asRSyntaxNode();
+        return getFunction() == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : getFunction().asRSyntaxNode();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
index 1a81c60bc464b40869f22733cefd740ec0181f9b..49863fcd9a3f8270f41307e31e8798d1e826fb5c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
@@ -117,7 +117,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         return sourceSection;
     }
 
-    @Child private ForcePromiseNode functionNode;
+    @Child private RNode functionNode;
     @Child private RNode special;
 
     private final RSyntaxNode[] arguments;
@@ -139,7 +139,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         this.sourceSection = sourceSection;
         this.expectedFunction = expectedFunction;
         this.special = special;
-        this.functionNode = new ForcePromiseNode(functionNode);
+        this.functionNode = functionNode;
         this.arguments = arguments;
         this.signature = signature;
     }
@@ -272,7 +272,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
     }
 
     private RCallNode getRCallNode(RSyntaxNode[] newArguments) {
-        return RCallNode.createCall(sourceSection, functionNode == null ? null : functionNode.getValueNode(), signature, newArguments);
+        return RCallNode.createCall(sourceSection, functionNode, signature, newArguments);
     }
 
     private RCallNode getRCallNode() {
@@ -300,8 +300,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
 
     @Override
     public RSyntaxElement getSyntaxLHS() {
-        ForcePromiseNode func = functionNode;
-        return func == null || func.getValueNode() == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : func.getValueNode().asRSyntaxNode();
+        return functionNode == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : functionNode.asRSyntaxNode();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java
index e1902ab85e28fbf91f66c6036849514b7c6c7ddf..8fb51170f9cad3819b28b72e310e239459cd4e99 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RPromise;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 /**
@@ -54,24 +55,24 @@ public final class RCallerHelper {
      * @param arguments array with arguments and corresponding names. This method strips any
      *            {@code RMissing} arguments and unrolls all varargs within the arguments array.
      */
-    public static Supplier<RSyntaxNode> createFromArguments(RFunction function, RArgsValuesAndNames arguments) {
+    public static Supplier<RSyntaxElement> createFromArguments(RFunction function, RArgsValuesAndNames arguments) {
         return createFromArgumentsInternal(function, arguments);
     }
 
     /**
      * @see #createFromArguments(RFunction, RArgsValuesAndNames)
      */
-    public static Supplier<RSyntaxNode> createFromArguments(String function, RArgsValuesAndNames arguments) {
+    public static Supplier<RSyntaxElement> createFromArguments(String function, RArgsValuesAndNames arguments) {
         return createFromArgumentsInternal(function, arguments);
     }
 
-    public static Supplier<RSyntaxNode> createFromArgumentsInternal(final Object function, final RArgsValuesAndNames arguments) {
-        return new Supplier<RSyntaxNode>() {
+    public static Supplier<RSyntaxElement> createFromArgumentsInternal(final Object function, final RArgsValuesAndNames arguments) {
+        return new Supplier<RSyntaxElement>() {
 
-            RSyntaxNode syntaxNode = null;
+            RSyntaxElement syntaxNode = null;
 
             @Override
-            public RSyntaxNode get() {
+            public RSyntaxElement get() {
                 if (syntaxNode == null) {
                     int length = 0;
                     for (int i = 0; i < arguments.getLength(); i++) {
@@ -122,13 +123,13 @@ public final class RCallerHelper {
     /**
      * This method calculates the signature of the permuted arguments lazily.
      */
-    public static Supplier<RSyntaxNode> createFromArguments(String function, long[] preparePermutation, Object[] suppliedArguments, ArgumentsSignature suppliedSignature) {
-        return new Supplier<RSyntaxNode>() {
+    public static Supplier<RSyntaxElement> createFromArguments(String function, long[] preparePermutation, Object[] suppliedArguments, ArgumentsSignature suppliedSignature) {
+        return new Supplier<RSyntaxElement>() {
 
-            RSyntaxNode syntaxNode = null;
+            RSyntaxElement syntaxNode = null;
 
             @Override
-            public RSyntaxNode get() {
+            public RSyntaxElement get() {
                 if (syntaxNode == null) {
                     Object[] values = new Object[preparePermutation.length];
                     String[] names = new String[preparePermutation.length];
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java
index f4bd0702a18bac1280a0613bd07463251c42fadf..e148ee23a00458c5cb45193e1de508c8128a7178 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/MissingNode.java
@@ -197,7 +197,7 @@ public final class MissingNode extends OperatorNode {
         if (level == null && readVarArgs == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             if (args.length != 1) {
-                throw RError.error(this, Message.ARGUMENTS_PASSED, args.length, "missing", 1);
+                throw RError.error(this, Message.ARGUMENTS_PASSED, args.length, "'missing'", 1);
             }
             RSyntaxElement arg = args[0];
             if (!(arg instanceof RSyntaxLookup)) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
index e5315d7410c862e2c6038a5a747fcf663aab322c..c20ab69256fd7633f839275c9f7ebe88f9db6cbc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
@@ -114,4 +114,12 @@ public final class SetVisibilityNode extends Node {
         CompilerAsserts.neverPartOfCompilation();
         frame.setBoolean(frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.Visibility, FrameSlotKind.Boolean), caller.getVisibility());
     }
+
+    /**
+     * Slow-path version of {@link #execute(Frame, boolean)}.
+     */
+    public static void executeSlowPath(Frame frame, boolean visibility) {
+        CompilerAsserts.neverPartOfCompilation();
+        frame.setBoolean(frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.Visibility, FrameSlotKind.Boolean), visibility);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
index 4be981a574ff0db8c4c8bfb736f99a60452b1748..298d82873a04bbefda07c6788471b543234a7c10 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
@@ -37,6 +37,7 @@ import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 // transcribed from /src/library/methods/src/methods_list_dispatch.c (R_loadMethod function)
@@ -121,7 +122,7 @@ abstract class LoadMethod extends RBaseNode {
             } else {
                 currentFunction = (RFunction) loadMethodFind.execute(frame, methodsEnv.getFrame(methodsFrameAccessProfile));
             }
-            RSyntaxNode originalCall = RASTUtils.getOriginalCall(this);
+            RSyntaxElement originalCall = RASTUtils.getOriginalCall(this);
             RCaller caller = originalCall == null ? RCaller.createInvalid(frame) : RCaller.create(frame, originalCall);
             if (cached.profile(currentFunction == loadMethodFunction)) {
                 // TODO: technically, someone could override loadMethod function and access the
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java
index 9d9834d6b5cb7aa350d0915b4ccd78d0767ab9d7..6771af91b7f7403faed55595e3efe24138cdbb9f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java
@@ -25,7 +25,7 @@ package com.oracle.truffle.r.runtime;
 import java.util.function.Supplier;
 
 import com.oracle.truffle.api.frame.Frame;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 
 /**
  * Represents the caller of a function and stored in {@link RArguments}. A value of this type never
@@ -72,9 +72,9 @@ public final class RCaller {
         return parent;
     }
 
-    public RSyntaxNode getSyntaxNode() {
+    public RSyntaxElement getSyntaxNode() {
         assert payload != null && !(payload instanceof RCaller) : payload == null ? "null RCaller" : "promise RCaller";
-        return payload instanceof RSyntaxNode ? (RSyntaxNode) payload : (RSyntaxNode) ((Supplier<?>) payload).get();
+        return payload instanceof RSyntaxElement ? (RSyntaxElement) payload : (RSyntaxElement) ((Supplier<?>) payload).get();
     }
 
     public boolean isValidCaller() {
@@ -97,22 +97,22 @@ public final class RCaller {
         return new RCaller(depthFromFrame(callingFrame), parent, null);
     }
 
-    public static RCaller create(Frame callingFrame, RSyntaxNode node) {
+    public static RCaller create(Frame callingFrame, RSyntaxElement node) {
         assert node != null;
         return new RCaller(callingFrame, node);
     }
 
-    public static RCaller create(Frame callingFrame, RCaller parent, RSyntaxNode node) {
+    public static RCaller create(Frame callingFrame, RCaller parent, RSyntaxElement node) {
         assert node != null;
         return new RCaller(depthFromFrame(callingFrame), parent, node);
     }
 
-    public static RCaller create(Frame callingFrame, Supplier<RSyntaxNode> supplier) {
+    public static RCaller create(Frame callingFrame, Supplier<RSyntaxElement> supplier) {
         assert supplier != null;
         return new RCaller(callingFrame, supplier);
     }
 
-    public static RCaller create(Frame callingFrame, RCaller parent, Supplier<RSyntaxNode> supplier) {
+    public static RCaller create(Frame callingFrame, RCaller parent, Supplier<RSyntaxElement> supplier) {
         assert supplier != null;
         return new RCaller(depthFromFrame(callingFrame), parent, supplier);
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 290c7a823ce0a2b59de62fd1c4aceadaf23ef3ca..2f152c4f51da159ede1efa0f1ba26154010f00d8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -572,7 +572,7 @@ public final class RError extends RuntimeException {
         SUBSCRIPT_TYPES("incompatible types (from %s to %s) in [[ assignment"),
         INCOMPATIBLE_METHODS("incompatible methods (\"%s\", \"%s\") for \"%s\""),
         RECURSIVE_INDEXING_FAILED("recursive indexing failed at level %d"),
-        ARGUMENTS_PASSED("%d arguments passed to '%s' which requires %d"),
+        ARGUMENTS_PASSED("%d arguments passed to %s which requires %d"),
         ARGUMENTS_PASSED_0_1("0 arguments passed to '%s' which requires 1"),
         ARGUMENTS_PASSED_INTERNAL_0_1("0 arguments passed to .Internal(%s) which requires 1"),
         ARGUMENT_IGNORED("argument '%s' will be ignored"),
@@ -759,6 +759,7 @@ public final class RError extends RuntimeException {
         ATTEMPT_TO_REPLICATE_NO_VECTOR("attempt to replicate non-vector"),
         INCORRECT_ARG_TYPE("incorrect type for %s argument"),
         INVALID_ARG_OF_LENGTH("invalid %s argument of length %d"),
+        INVALID_ARG("invalid %s argument"),
         INVALID_FILENAME_PATTERN("invalid filename pattern"),
         INVALID_FILE_EXT("invalid file extension"),
         NO("no '%s'"),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java
index 208b455e8791b694d03b44ae28c913044c9061b3..b24242d83805613c6f717e4bf4d3ad420d401daf 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java
@@ -101,7 +101,8 @@ public final class EvaluatedArgumentsVisitor extends RSyntaxVisitor<Info> {
                     if (builtin != null && builtin.getKind() == RBuiltinKind.INTERNAL) {
                         ArgumentsSignature signature = builtin.getSignature();
                         if (signature.getVarArgCount() == 0) {
-                            assert innerArguments.length == signature.getLength();
+                            // holds only for well-formed code, so we cannot rely on it:
+                            // assert innerArguments.length == signature.getLength();
                         } else {
                             assert signature.getVarArgCount() == 1 : signature;
                             assert innerArguments.length == signature.getLength() || signature.getVarArgIndex() == signature.getLength() - 1 : signature;
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 56bce3bc119bc4027798338a14af68e23e6d0538..f8e922a309213fb0ed51df55aff111a0c07e99cb 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -33225,11 +33225,11 @@ a     f g
   bar 4 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_nchar.testNChar#
-#{ .Internal(nchar('ff', 'chars', FALSE)) }
+#{ .Internal(nchar('ff', 'chars', FALSE, FALSE)) }
 [1] 2
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_nchar.testNChar#
-#{ .Internal(nchar(c(10,130), 'chars', FALSE)) }
+#{ .Internal(nchar(c(10,130), 'chars', FALSE, FALSE)) }
 [1] 2 3
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_nchar.testNChar#
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_nchar.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_nchar.java
index 232fe1a6a324287bbc63a5b50dc842a2c459bc65..a55986b74187308bfc40b5ade993b58e108b5314 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_nchar.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_nchar.java
@@ -82,8 +82,8 @@ public class TestBuiltin_nchar extends TestBase {
         assertEval("{ nchar(c(\"hello\", \"hi\")) }");
         assertEval("{ nchar(c(\"hello\", \"hi\", 10, 130)) }");
         assertEval("{ nchar(c(10,130)) }");
-        assertEval("{ .Internal(nchar(c(10,130), 'chars', FALSE)) }");
-        assertEval("{ .Internal(nchar('ff', 'chars', FALSE)) }");
+        assertEval("{ .Internal(nchar(c(10,130), 'chars', FALSE, FALSE)) }");
+        assertEval("{ .Internal(nchar('ff', 'chars', FALSE, FALSE)) }");
 
         assertEval("v <- c(a=1,b=1234,c='ff',d='gg'); dim(v) <- c(foo=2,bar=2); dimnames(v) <- list(a=c('foo', 'bar'), n=c('f','g')); nchar(v)");
     }