diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 6837ec9a35d7193ad1bb68ade5755c93c88eee71..6c2f34cee14ff03ff4c37888c6de0e286e6b0296 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -97,7 +97,6 @@ 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.data.RPromise;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -436,7 +435,7 @@ final class REngine implements Engine, Engine.Timings {
 
     @Override
     @TruffleBoundary
-    public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args) {
+    public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, boolean evalPromises, ArgumentsSignature names, Object... args) {
         assert frame == null || caller != null;
         MaterializedFrame actualFrame = frame;
         if (actualFrame == null) {
@@ -449,15 +448,17 @@ final class REngine implements Engine, Engine.Timings {
             }
         }
         RArgsValuesAndNames reorderedArgs = CallMatcherGenericNode.reorderArguments(args, func,
-                        names == null ? ArgumentsSignature.empty(args.length) : ArgumentsSignature.get(names.getDataWithoutCopying()), RError.NO_CALLER);
+                        names == null ? ArgumentsSignature.empty(args.length) : names, RError.NO_CALLER);
         Object[] newArgs = reorderedArgs.getArguments();
-        for (int i = 0; i < newArgs.length; i++) {
-            Object arg = newArgs[i];
-            if (arg instanceof RPromise) {
-                newArgs[i] = PromiseHelperNode.evaluateSlowPath(null, (RPromise) arg);
+        if (evalPromises) {
+            for (int i = 0; i < newArgs.length; i++) {
+                Object arg = newArgs[i];
+                if (arg instanceof RPromise) {
+                    newArgs[i] = PromiseHelperNode.evaluateSlowPath(null, (RPromise) arg);
+                }
             }
         }
-        return CallRFunctionNode.executeSlowpath(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, newArgs, null);
+        return CallRFunctionNode.executeSlowpath(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, newArgs, reorderedArgs.getSignature(), null);
     }
 
     private Object evalNode(RSyntaxElement exprRep, REnvironment envir, RCaller caller) {
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 7c242944350bfebdceda6e44619e119485e7d8c3..454eafb417159396083e0e72333299f393f513ff 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
@@ -367,7 +367,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
     public Object callback(RFunction f, Object[] args) {
         boolean gd = RContext.getInstance().stateInstrumentation.setDebugGloballyDisabled(true);
         try {
-            return RContext.getEngine().evalFunction(f, null, null, null, args);
+            return RContext.getEngine().evalFunction(f, null, null, true, null, args);
         } catch (ReturnException ex) {
             // cannot throw return exceptions further up.
             return ex.getResult();
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java
index eaeeb329ea451ca404e91fe0c99f69592298e2e8..3d2a62fd7f04978fd81d4a64892f495e9a2200ce 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java
@@ -99,7 +99,7 @@ public class JLineConsoleCompleter implements Completer {
             env.safePut("token", buffer.substring(start, cursor));
 
             MaterializedFrame callingFrame = REnvironment.globalEnv().getFrame();
-            RContext.getEngine().evalFunction(completeToken, callingFrame, RCaller.createInvalid(callingFrame), null, new Object[]{});
+            RContext.getEngine().evalFunction(completeToken, callingFrame, RCaller.createInvalid(callingFrame), true, null, new Object[]{});
 
             o = env.get("comps");
             if (!(o instanceof RAbstractStringVector)) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java
index a2c92c4c538b61773a56f0198121a8525c4b4606..efd87be667163e281801070eb5c2804b37d73378 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java
@@ -129,7 +129,7 @@ public final class GridContext {
             internalCode = RInternalCode.lookup(RContext.getInstance(), "grid", RInternalCode.loadSourceRelativeTo(LInitGrid.class, "fastrGrid.R"));
         }
         RFunction redrawAll = internalCode.lookupFunction(functionName);
-        return RContext.getEngine().evalFunction(redrawAll, REnvironment.baseEnv().getFrame(), RCaller.topLevel, null, args);
+        return RContext.getEngine().evalFunction(redrawAll, REnvironment.baseEnv().getFrame(), RCaller.topLevel, true, null, args);
     }
 
     private static final class DeviceAndState {
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 ec10b5b52c2799325428a28f97b2791f025321dd..ce6d340ec5cb2eb59e18ed0f4ad03e5748e25fc2 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
@@ -28,25 +28,43 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 
+import java.util.Arrays;
+
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.FrameSlot;
+import com.oracle.truffle.api.frame.FrameSlotKind;
+import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
+import com.oracle.truffle.r.nodes.access.ConstantNode;
+import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.DoCallNodeGen.DoCallInternalNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctions.Get;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen;
-import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
+import com.oracle.truffle.r.nodes.function.RCallerHelper;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.RArguments;
+import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.RDispatch;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -58,24 +76,18 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseState;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 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.env.frame.FrameSlotChangeMonitor;
+import com.oracle.truffle.r.runtime.env.frame.RFrameSlot;
 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.Arg4 implements InternalRSyntaxNodeChildren {
 
-    @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
-
-    private final BranchProfile containsRLanguageProfile = BranchProfile.create();
-    private final BranchProfile containsRSymbolProfile = BranchProfile.create();
-
-    @Child private RExplicitCallNode call = RExplicitCallNode.create();
-
     static {
         Casts casts = new Casts(DoCall.class);
         casts.arg("what").defaultError(Message.MUST_BE_STRING_OR_FUNCTION, "what").mustBe(instanceOf(RFunction.class).or(stringValue()));
@@ -88,72 +100,180 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta
         return GetNodeGen.create();
     }
 
+    // Note: quote tells us if symbols in args list should be interpreted as symbols (quote=TRUE) or
+    // they should be interpreted as read of given symbol from the given environment.
+
     @Specialization
     protected Object doCall(VirtualFrame frame, RAbstractStringVector what, RList argsAsList, boolean quote, REnvironment env,
+                    @Cached("create()") DoCallInternal internal,
                     @Cached("createGet()") Get getNode) {
         if (what.getLength() != 1) {
             throw error(RError.Message.MUST_BE_STRING_OR_FUNCTION, "what");
         }
+        // Note: if the function is in fact a promise, we are evaluating it here slightly earlier
+        // than GNU R. It should not a be a problem.
         RFunction func = (RFunction) getNode.execute(frame, what.getDataAt(0), env, RType.Function.getName(), true);
-        return doCall(frame, func, argsAsList, quote, env);
+        return doCall(frame, func, argsAsList, quote, env, internal);
     }
 
     @Specialization
-    protected Object doCall(VirtualFrame frame, RFunction func, RList argsAsList, boolean quote, REnvironment env) {
-        /*
-         * To re-create the illusion of a normal call, turn the values in argsAsList into promises.
+    protected Object doCall(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env,
+                    @Cached("create()") DoCallInternal internal) {
+        return internal.execute(virtualFrame, func, argsAsList, quote, env);
+    }
+
+    protected abstract static class DoCallInternal extends Node {
+        @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
+        @Child private SetVisibilityNode setVisibilityNode = SetVisibilityNode.create();
+
+        public static DoCallInternal create() {
+            return DoCallInternalNodeGen.create();
+        }
+
+        public abstract Object execute(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env);
+
+        protected final ArgumentsSignature getArgsNames(RList argsAsList) {
+            ArgumentsSignature signature = ArgumentsSignature.fromNamesAttribute(getNamesNode.getNames(argsAsList));
+            return signature == null ? ArgumentsSignature.empty(argsAsList.getLength()) : signature;
+        }
+
+        /**
+         * Fast version that works only for simple cases. It does not explicitly create the AST and
+         * evaluate it, but instead it directly implements what the execution of such AST would do.
          */
-        Object[] argValues = argsAsList.getDataCopy();
-        RStringVector n = getNamesNode.getNames(argsAsList);
-        ArgumentsSignature signature;
-        if (n == null) {
-            signature = ArgumentsSignature.empty(argValues.length);
-        } else {
-            String[] argNames = new String[argValues.length];
+        @Specialization(guards = "isSimple(func, argsAsList)")
+        public Object doSimple(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env,
+                        @Cached("create()") ShareObjectNode shareObjectNode,
+                        @Cached("createBinaryProfile()") ConditionProfile quoteProfile,
+                        @Cached("create()") BranchProfile containsRSymbolProfile,
+                        @Cached("createClassProfile()") ValueProfile frameAccessProfile) {
+            Object[] argValuesData = argsAsList.getDataWithoutCopying();
+            Object[] argValues = argValuesData;
+            MaterializedFrame envFrame = env.getFrame(frameAccessProfile).materialize();
+            if (quoteProfile.profile(!quote)) {
+                argValues = Arrays.copyOf(argValuesData, argValuesData.length);
+                for (int i = 0; i < argValues.length; i++) {
+                    Object arg = argValues[i];
+                    if (arg instanceof RSymbol) {
+                        containsRSymbolProfile.enter();
+                        RSymbol symbol = (RSymbol) arg;
+                        if (symbol.getName().isEmpty()) {
+                            argValues[i] = REmpty.instance;
+                        } else {
+                            argValues[i] = createLookupPromise(envFrame, symbol);
+                        }
+                    }
+                }
+            }
             for (int i = 0; i < argValues.length; i++) {
-                String name = n.getDataAt(i);
-                argNames[i] = name == null ? null : name.isEmpty() ? null : name;
+                shareObjectNode.execute(argValues[i]);
+            }
+            ArgumentsSignature signature = getArgsNames(argsAsList);
+            RCaller caller = RCaller.create(virtualFrame, RCallerHelper.createFromArguments(func, new RArgsValuesAndNames(argValues, signature)));
+            try {
+                Object resultValue = RContext.getEngine().evalFunction(func, envFrame, caller, false, signature, argValues);
+                setVisibilityNode.execute(virtualFrame, getVisibility(envFrame));
+                return resultValue;
+            } finally {
+                for (int i = 0; i < argValues.length; i++) {
+                    ShareObjectNode.unshare(argValues[i]);
+                }
             }
-            signature = ArgumentsSignature.get(argNames);
         }
-        if (!quote) {
+
+        protected static boolean isSimple(RFunction function, RList args) {
+            RBuiltinDescriptor builtin = function.getRBuiltin();
+            if (builtin != null && builtin.getDispatch() != RDispatch.DEFAULT) {
+                CompilerDirectives.transferToInterpreter();
+                return false;
+            }
+            for (int i = 0; i < args.getLength(); i++) {
+                if (args.getDataAt(i) instanceof RLanguage) {
+                    CompilerDirectives.transferToInterpreter();
+                    // Note: language is tricky because of formulae, which are language that is
+                    // really not meant to be evaluated again in a different frame than the one were
+                    // the were evaluated for the first time. The solution should be to clone the
+                    // language's rep and get its nodes in uninitilized state, but that does not
+                    // work for some reason.
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @TruffleBoundary
+        private static RPromise createLookupPromise(MaterializedFrame callerFrame, RSymbol symbol) {
+            Closure closure = RPromise.Closure.create(RContext.getASTBuilder().lookup(RSyntaxNode.SOURCE_UNAVAILABLE, symbol.getName(), false).asRNode());
+            return RDataFactory.createPromise(PromiseState.Supplied, closure, callerFrame);
+        }
+
+        @TruffleBoundary
+        private boolean getVisibility(MaterializedFrame envFrame) {
+            FrameSlot envVisibilitySlot = FrameSlotChangeMonitor.findOrAddFrameSlot(envFrame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean);
+            if (envVisibilitySlot != null) {
+                try {
+                    return envFrame.getBoolean(envVisibilitySlot);
+                } catch (FrameSlotTypeException e) {
+                    throw RInternalError.shouldNotReachHere();
+                }
+            }
+            return false;
+        }
+
+        @Specialization(guards = "!isSimple(func, argsAsList)")
+        public Object doGeneric(VirtualFrame virtualFrame, RFunction func, RList argsAsList, boolean quote, REnvironment env) {
+            CallResult result = doCallGeneric(func, argsAsList.getDataWithoutCopying(), getArgsNames(argsAsList), quote, RArguments.getCall(virtualFrame), env);
+            setVisibilityNode.execute(virtualFrame, result.visibility);
+            return result.value;
+        }
+
+        @TruffleBoundary
+        private CallResult doCallGeneric(RFunction function, Object[] argValues, ArgumentsSignature argsSignature, boolean quote, RCaller call, REnvironment env) {
+            RSyntaxNode[] argsConstants = new RSyntaxNode[argValues.length];
             for (int i = 0; i < argValues.length; i++) {
-                Object arg = argValues[i];
-                if (arg instanceof RLanguage) {
-                    containsRLanguageProfile.enter();
-                    RLanguage lang = (RLanguage) arg;
-                    argValues[i] = createRLanguagePromise(env.getFrame().materialize(), lang);
-                } else if (arg instanceof RSymbol) {
-                    containsRSymbolProfile.enter();
-                    RSymbol symbol = (RSymbol) arg;
-                    if (symbol.getName().isEmpty()) {
-                        argValues[i] = REmpty.instance;
+                if (!quote && argValues[i] instanceof RLanguage) {
+                    argsConstants[i] = ((RLanguage) argValues[i]).getRep().asRSyntaxNode();
+                } else if (!quote && argValues[i] instanceof RSymbol) {
+                    RSymbol symbol = (RSymbol) argValues[i];
+                    if (symbol.isMissing()) {
+                        argsConstants[i] = ConstantNode.create(REmpty.instance);
                     } else {
-                        argValues[i] = createLookupPromise(env.getFrame().materialize(), symbol);
+                        argsConstants[i] = ReadVariableNode.create(((RSymbol) argValues[i]).getName());
                     }
+                } else {
+                    argsConstants[i] = ConstantNode.create(argValues[i]);
                 }
             }
-        }
-        for (int i = 0; i < argValues.length; i++) {
-            ShareObjectNode.share(argValues[i]);
-        }
-        try {
-            return call.execute(frame, func, new RArgsValuesAndNames(argValues, signature));
-        } finally {
             for (int i = 0; i < argValues.length; i++) {
-                ShareObjectNode.unshare(argValues[i]);
+                ShareObjectNode.share(argValues[i]);
+            }
+            RLanguage lang = RDataFactory.createLanguage(RASTUtils.createCall(ConstantNode.create(function), true, argsSignature, argsConstants).asRNode());
+            try {
+                Object resultValue = RContext.getEngine().eval(lang, env, call);
+                MaterializedFrame envFrame = env.getFrame();
+                FrameSlot envVisibilitySlot = FrameSlotChangeMonitor.findOrAddFrameSlot(envFrame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean);
+                boolean resultVisibility = false;
+                if (envVisibilitySlot != null) {
+                    resultVisibility = envFrame.getBoolean(envVisibilitySlot);
+                }
+                return new CallResult(resultValue, resultVisibility);
+            } catch (FrameSlotTypeException e) {
+                throw RInternalError.shouldNotReachHere();
+            } finally {
+                for (int i = 0; i < argValues.length; i++) {
+                    ShareObjectNode.unshare(argValues[i]);
+                }
             }
         }
-    }
 
-    @TruffleBoundary
-    private static RPromise createLookupPromise(MaterializedFrame callerFrame, RSymbol symbol) {
-        Closure closure = RPromise.Closure.create(RContext.getASTBuilder().lookup(RSyntaxNode.SOURCE_UNAVAILABLE, symbol.getName(), false).asRNode());
-        return RDataFactory.createPromise(PromiseState.Supplied, closure, callerFrame);
-    }
+        private static final class CallResult {
+            public final Object value;
+            public final boolean visibility;
 
-    @TruffleBoundary
-    private static RPromise createRLanguagePromise(MaterializedFrame callerFrame, RLanguage lang) {
-        return RDataFactory.createPromise(PromiseState.Supplied, RPromise.Closure.create(RASTUtils.cloneNode(lang.getRep())), callerFrame);
+            CallResult(Object value, boolean visibility) {
+                this.value = value;
+                this.visibility = visibility;
+            }
+        }
     }
 }
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 873b10c3c1e1777b846da88ff8d5d53e37c9ea5f..3c217de32aa4b145a881ee4c6bf20e5f8a6d4a02 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
@@ -93,7 +93,7 @@ public class PrintFunctions {
                         @Cached("createShowFunction(frame)") RFunction showFunction) {
             if (noOpt) {
                 // S4 should only be called in case noOpt is true
-                RContext.getEngine().evalFunction(showFunction, null, null, null, o);
+                RContext.getEngine().evalFunction(showFunction, null, null, true, null, o);
             } else {
                 printDefault(showFunction, digits, quote, naPrint, printGap, right, max, useSource, noOpt);
             }
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 0334382ddc1d606ea1bbd9dfb1ba213dda04c6cc..cdd90a090899456d7e339fbb92da3e3f5d0f06a8 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
@@ -97,7 +97,7 @@ public abstract class StandardGeneric extends RBuiltinNode.Arg2 {
             // and this slow path should not be executed again
             REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods");
             RFunction currentFunction = ReadVariableNode.lookupFunction(".getMethodsTable", methodsEnv.getFrame(), true, true);
-            mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, def);
+            mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), true, null, def);
         }
         RList sigArgs = (RList) readSigARgs.execute(null, fnFrame);
         int sigLength = (int) castIntScalar.doCast(readSigLength.execute(null, fnFrame));
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 560b5fc442c9b3f045b699ee24fb4b268c34dd5e..083a7bcbe272cfe059e3f61900662e65c0c086fc 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
@@ -111,7 +111,7 @@ public abstract class UpdateSlot extends RBuiltinNode.Arg3 {
                                 checkSlotAssignFunction.getEnclosingFrame(), null);
             } else {
                 // slow path
-                RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.createInvalid(frame), null, objClass, name, valClass);
+                RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.createInvalid(frame), true, null, objClass, name, valClass);
             }
         }
     }
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 abac7f57b85b22c01cf560bddb9d11ab29e4fe4f..a6f492fda37610985d91e463e67177c96dd1f5f5 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
@@ -67,6 +67,6 @@ public abstract class Xtfrm extends RBuiltinNode.Arg1 {
             env = REnvironment.createEnclosingEnvironments(frame.materialize());
         }
         RFunction func = (RFunction) getNode.execute(frame, "xtfrm.default", env, RType.Function.getName(), true);
-        return RContext.getEngine().evalFunction(func, null, null, null, x);
+        return RContext.getEngine().evalFunction(func, null, null, true, null, x);
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java
index 2ff2c2bf36eaaf8fa1c1123cf8b40b2dec33b8e6..173799ff0b9808f9564f0908b66fd78ca324fc5c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java
@@ -63,7 +63,7 @@ final class S4ObjectPrinter implements ValuePrinter<RS4Object> {
 
     static void printS4(PrintContext printCtx, Object o) {
         Frame frame = com.oracle.truffle.r.runtime.Utils.getActualCurrentFrame();
-        RContext.getEngine().evalFunction(createShowFunction(frame), null, null, null, o);
+        RContext.getEngine().evalFunction(createShowFunction(frame), null, null, true, null, o);
         // The show function prints an additional new line character. The following attribute
         // instructs the ValuePrinter.println method not to print the new line since it was
         // already printed.
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
index 1d8fccff965444f3ffc3f9f100a442e4dfab6db3..61f7c1074d7076934b15812a134481813c0953eb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
@@ -76,7 +76,7 @@ public abstract class AccessSlotNode extends RBaseNode {
                 // TODO: any way to cache it or use a mechanism similar to overrides?
                 REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods");
                 RFunction dataPart = getDataPartFunction(methodsNamespace);
-                return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), null, object);
+                return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), true, null, object);
             } else if (name == RRuntime.NAMES_ATTR_KEY && object instanceof RAbstractVector) {
                 assert false; // RS4Object can never be a vector?
                 return RNull.instance;
@@ -126,7 +126,7 @@ public abstract class AccessSlotNode extends RBaseNode {
         // TODO: any way to cache it or use a mechanism similar to overrides?
         REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods");
         RFunction dataPart = getDataPartFunction(methodsNamespace);
-        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), null, object);
+        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), true, null, object);
     }
 
     // this is really a fallback specialization but @Fallback does not work here (because of the
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
index 59d8ab2c49c12060a5c96d63205779293f1f01e2..f895c1d2bb2c1a2fbd0d82ebf19e56f2ca2022ec 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
@@ -59,7 +59,7 @@ public abstract class UpdateSlotNode extends RBaseNode {
         REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods");
         Object f = methodsNamespace.findFunction(SET_DATA_PART);
         RFunction dataPart = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(SET_DATA_PART, f);
-        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.createInvalid(null), null, object, prepareValue(value), RRuntime.LOGICAL_TRUE);
+        return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.createInvalid(null), true, null, object, prepareValue(value), RRuntime.LOGICAL_TRUE);
     }
 
     protected boolean isData(String name) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
index a6e270047ddfc99e8f2ab0d7170fb53245a143d2..5e88b23d2c8ba06309f6249d69c0fd12e26bd681 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java
@@ -44,6 +44,7 @@ import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.ffi.ParseResult.ParseStatus;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RCleanUp;
@@ -204,7 +205,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     public Object R_do_MAKE_CLASS(Object clazz) {
         String name = "getClass";
         RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(name, REnvironment.getRegisteredNamespace("methods").get(name));
-        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz);
+        return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), true, null, clazz);
     }
 
     @Override
@@ -733,10 +734,11 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
             RFunction f = (RFunction) l.car();
             Object args = l.cdr();
             if (args == RNull.instance) {
-                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, null, new Object[0]);
+                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, true, null, new Object[0]);
             } else {
                 RList argsList = ((RPairList) args).toRList();
-                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, argsList.getNames(),
+                result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, true,
+                                ArgumentsSignature.fromNamesAttribute(argsList.getNames()),
                                 argsList.getDataNonShared());
             }
         } else {
@@ -794,7 +796,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
     @Override
     public int R_compute_identical(Object x, Object y, int flags) {
         RFunction indenticalBuiltin = RContext.lookupBuiltin("identical");
-        Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
+        Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, true, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))),
                         RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0))));
         return (int) res;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
index 1a6f9101103bbd7fd61b4af88d14b47a42edbf11..db25097a00b0d4d46095db9db9ec3ee1fc72274c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
@@ -232,7 +232,6 @@ public class ArgumentMatcher {
         }, index -> evaluatedArgs.getSignature().getName(index), null);
 
         Object[] evaledArgs = new Object[match.resultPermutation.length];
-
         for (int formalIndex = 0; formalIndex < match.resultPermutation.length; formalIndex++) {
             int suppliedIndex = match.resultPermutation[formalIndex];
 
@@ -260,7 +259,7 @@ public class ArgumentMatcher {
                 evaledArgs[formalIndex] = evaluatedArgs.getArgument(suppliedIndex);
             }
         }
-        return new RArgsValuesAndNames(evaledArgs, formals.getSignature());
+        return new RArgsValuesAndNames(evaledArgs, match.resultSignature);
     }
 
     /**
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
index dcaab1397e5254f321c47f018e8ef863c3b4a3dc..00a81a5535eb4c606c8de0f490e4841b5d119a3f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
@@ -257,7 +257,7 @@ abstract class S4Class extends RBaseNode {
             // the assumption here is that the R function can only return either a String or
             // RStringVector
             s4Extends = (RStringVector) castToVector.doCast(
-                            RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), null, classAttr));
+                            RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(null, RASTUtils.getOriginalCall(this)), true, null, classAttr));
             RContext.getInstance().putS4Extends(classAttr, s4Extends);
         }
         return s4Extends;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
index 02a315c52e90c6df7363da15e1a207af7b8876c0..ee1b587d0e3ccb584dd31d81d7bd75f9d612986d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
@@ -65,8 +65,17 @@ public final class CallRFunctionNode extends Node {
         return callNode;
     }
 
+    public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, DispatchArgs dispatchArgs) {
+        Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, suppliedSignature, function.getEnclosingFrame(), dispatchArgs);
+        return executeSlowpath(function, caller, callerFrame, callArgs);
+    }
+
     public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, DispatchArgs dispatchArgs) {
         Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, dispatchArgs);
+        return executeSlowpath(function, caller, callerFrame, callArgs);
+    }
+
+    private static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] callArgs) {
         try {
             return function.getTarget().call(callArgs);
         } finally {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
index 9d4fdeb7f07be32e3bfa3d428564c36b170dcd6a..4098d1e5d501124ac77f8186066ce82ecb77dcb9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java
@@ -73,7 +73,7 @@ public abstract class DispatchGeneric extends RBaseNode {
             CompilerDirectives.transferToInterpreterAndInvalidate();
             REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods");
             RFunction currentFunction = ReadVariableNode.lookupFunction(".InheritForDispatch", methodsEnv.getFrame(), true, true);
-            method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), null, classes, fdef, mtable);
+            method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), true, null, classes, fdef, mtable);
         }
         method = loadMethod.executeRFunction(frame, method, fname);
         Object ret = executeMethod.executeObject(frame, method, fname);
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 236289defb37f1353359c34e785f0b5b943282d6..3780418d1675fe83fe3101d4ad6bdc6a021b14fd 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
@@ -136,7 +136,7 @@ abstract class LoadMethod extends RBaseNode {
                                 loadMethodFunction.getEnclosingFrame(), null);
             } else {
                 // slow path
-                ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, null, fdef, fname, REnvironment.frameToEnvironment(frame.materialize()));
+                ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, true, null, fdef, fname, REnvironment.frameToEnvironment(frame.materialize()));
             }
         } else {
             ret = fdef;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
index ca2ec69bbd8f5615607da8898b48296b20b6997d..ac69a5a14fd5a4ec37a529811733dbe1df51a437 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.r.runtime.data.RStringVector;
 
 public final class ArgumentsSignature implements Iterable<String> {
 
@@ -47,7 +48,7 @@ public final class ArgumentsSignature implements Iterable<String> {
     public static final int NO_VARARG = -1;
 
     @CompilationFinal(dimensions = 1) private static final ArgumentsSignature[] EMPTY_SIGNATURES = new ArgumentsSignature[32];
-    public static final ArgumentsSignature INVALID_SIGNATURE = new ArgumentsSignature(new String[]{"<<invalid>>"});
+    public static final ArgumentsSignature INVALID_SIGNATURE = new ArgumentsSignature(new String[]{"<<invalid>>"}, false);
 
     static {
         for (int i = 0; i < EMPTY_SIGNATURES.length; i++) {
@@ -55,12 +56,8 @@ public final class ArgumentsSignature implements Iterable<String> {
         }
     }
 
-    @TruffleBoundary
     public static ArgumentsSignature get(String... names) {
-        assert names != null;
-        ArgumentsSignature newSignature = new ArgumentsSignature(names);
-        ArgumentsSignature oldSignature = signatures.putIfAbsent(newSignature, newSignature);
-        return oldSignature != null ? oldSignature : newSignature;
+        return get(names, false);
     }
 
     public static ArgumentsSignature empty(int length) {
@@ -73,15 +70,41 @@ public final class ArgumentsSignature implements Iterable<String> {
         return get(new String[length]);
     }
 
+    /**
+     * Returns {@code null} if the the vector is {@code null}. Any empty string in the vector is
+     * converted to {@code null} value.
+     */
+    public static ArgumentsSignature fromNamesAttribute(RStringVector names) {
+        return names == null ? null : get(names.getDataWithoutCopying(), true);
+    }
+
+    @TruffleBoundary
+    private static ArgumentsSignature get(String[] names, boolean convertEmpty) {
+        assert names != null;
+        ArgumentsSignature newSignature = new ArgumentsSignature(names, convertEmpty);
+        ArgumentsSignature oldSignature = signatures.putIfAbsent(newSignature, newSignature);
+        return oldSignature != null ? oldSignature : newSignature;
+    }
+
     @CompilationFinal(dimensions = 1) private final String[] names;
     @CompilationFinal(dimensions = 1) private final int[] varArgIndexes;
     @CompilationFinal(dimensions = 1) private final boolean[] isVarArg;
     private final int varArgIndex;
     private final int nonNullCount;
 
-    private ArgumentsSignature(String[] names) {
-        this.names = Arrays.stream(names).map(s -> s == null || s == UNMATCHED ? s : s.intern()).toArray(String[]::new);
-        this.nonNullCount = (int) Arrays.stream(names).filter(s -> s != null).count();
+    private ArgumentsSignature(String[] names, boolean convertEmpty) {
+        this.names = new String[names.length];
+        int nonNullCount = 0;
+        for (int i = 0; i < names.length; i++) {
+            String s = names[i];
+            if (s == null || (s.isEmpty() && convertEmpty)) {
+                this.names[i] = null;
+                continue;
+            }
+            nonNullCount++;
+            this.names[i] = s == UNMATCHED ? s : s.intern();
+        }
+        this.nonNullCount = nonNullCount;
 
         int index = NO_VARARG;
         int count = 0;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
index ac0af78b884cfab4b846dbdea61cac73915befec..6913a4f10243e621613dcd5c67915e5b532eb991 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
@@ -356,7 +356,7 @@ public class RErrorHandling {
                         errorcallDfltWithCall(fromCall(call), Message.GENERIC, msg);
                     } else {
                         RFunction hf = (RFunction) h;
-                        RContext.getEngine().evalFunction(hf, null, null, null, cond);
+                        RContext.getEngine().evalFunction(hf, null, null, true, null, cond);
                     }
                 } else {
                     throw gotoExitingHandler(cond, call, entry);
@@ -524,7 +524,7 @@ public class RErrorHandling {
                             evaluatedArgs[i] = RMissing.instance;
                         }
                     }
-                    RContext.getEngine().evalFunction(errorFunction, null, null, null, evaluatedArgs);
+                    RContext.getEngine().evalFunction(errorFunction, null, null, true, null, evaluatedArgs);
                 } else if (errorExpr instanceof RLanguage || errorExpr instanceof RExpression) {
                     if (errorExpr instanceof RLanguage) {
                         RContext.getEngine().eval((RLanguage) errorExpr, materializedFrame);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index 8ee00ebb4a460f4cff2111a5a39047dc91e2fa30..85b7cd674b25d9306ebe7c1bc94c08fd13183f2d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -466,7 +466,7 @@ public class RSerialize {
                     // fast path through getRegisteredNamespace
                     Object namespace = REnvironment.getRegisteredNamespace(s.getDataAt(0));
                     if (namespace == null) {
-                        namespace = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, null, s, "");
+                        namespace = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, true, null, s, "");
                     }
                     return checkResult(addReadRef(namespace));
                 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
index 6c7f7f692cc73dc2134594d4f5c71f4bc65dd99d..fe6fc77fa95752f8dea4d2fced40aa64930cd326 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,13 +28,13 @@ import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.vm.PolyglotEngine;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
@@ -171,8 +171,12 @@ public interface Engine {
      * namespace, but the current stack is not empty. So when {@code frame} is not {@code null} a
      * {@code caller} should be passed to maintain the call stack correctly. {@code names} string
      * vector describing (optional) argument names
+     * 
+     * @param names signature of the given parameters, may be {@code null} in which case the empty
+     *            signature of correct cardinality shall be used.
+     * @param evalPromises whether to evaluate promises in args array before calling the function.
      */
-    Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args);
+    Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, boolean evalPromises, ArgumentsSignature names, Object... args);
 
     /**
      * Checks for the existence of (startup/shutdown) function {@code name} and, if present, invokes
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java
index f44d5c5222baf7632708d894ec6e08fea8c74a7f..892566e5bf11b2a9067369e42ae9b843a4f01afd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/ActiveBinding.java
@@ -27,7 +27,6 @@ import java.util.Objects;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RTruffleObject;
 import com.oracle.truffle.r.runtime.env.REnvironment;
@@ -64,11 +63,11 @@ public class ActiveBinding implements RTruffleObject {
     }
 
     public Object writeValue(Object value) {
-        return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), null, value);
+        return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), true, null, value);
     }
 
     public Object readValue() {
-        return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), RDataFactory.createEmptyStringVector());
+        return RContext.getEngine().evalFunction(function, REnvironment.baseEnv().getFrame(), RCaller.createInvalid(null), true, null);
     }
 
 }
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 a4a69155cacaecab5a2c1cd3f99735e0c92629e9..5c89154642282ef8112e8636bce9fda6e47c3a4a 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
@@ -22257,6 +22257,9 @@ Error in (function (x)  : object 'foo' not found
 #{ do.call("+", list(quote(1), 2))}
 [1] 3
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ do.call('+', list(data.frame(1), data.frame(2)), envir = new.env()); do.call('assign', list('a',2,new.env()), envir = new.env()); }
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
 #{ do.call(quote, list(quote(1)))}
 [1] 1
@@ -22269,6 +22272,22 @@ x
 #{ do.call(quote, list(quote(x+1)))}
 x + 1
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e); }
+[1] 42
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e, quote=T); }
+a
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ e <- new.env(); assign('foo', 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); }
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ e <- new.env(); assign('foo', function() 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); }
+[1] 42
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#Output.IgnoreErrorContext#
 #{ f <- function(x) x; do.call(f, list(quote(y + 1)))}
 Error in (function (x)  : object 'y' not found
@@ -22277,6 +22296,44 @@ Error in (function (x)  : object 'y' not found
 #{ f <- function(x) x; do.call(f, list(quote(y)))}
 Error in (function (x)  : object 'y' not found
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list()); bar(a=1,b=2,c=3); }
+[1] "a" "b" "c"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list(), envir=globalenv()); bar(a=1,b=2,c=3) }
+[1] "bar" "foo"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ foo <- function(a,b)  list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a,b), env=e); }
+$a
+[1] 0
+
+$b
+[1] 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ foo <- function(a,b)  list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a=as.name('a'),as.name('b')), env=e) }
+$a
+[1] 0
+
+$b
+[1] 1
+
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#{ foo <- function(a,b,c) { cat('foo called.'); list(a=a,b=b,c=c); }; side <- function() { cat('side effect!'); 42 }; do.call('foo', list(parse(text='side()')[[1]], 0, 0)); }
+foo called.side effect!$a
+[1] 42
+
+$b
+[1] 0
+
+$c
+[1] 0
+
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
 #{ x<-list(c(1,2)); do.call("as.matrix", x) }
      [,1]
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java
index 73fbac9e68fd11f22099a70addf59940d87cd915..c0003b48744895d87218edb6e67044f4c97b3992 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_docall.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -31,5 +31,17 @@ public class TestBuiltin_docall extends TestBase {
         assertEval("v1 <- as.numeric_version('3.0.0'); v2 <- as.numeric_version('3.1.0'); do.call('<', list(quote(v1), quote(v2)))");
         assertEval(Output.IgnoreErrorContext, "typeof(do.call(function(x) x, list(as.symbol('foo'))))");
         assertEval("typeof(do.call(function(x) x, list(as.symbol('foo')), quote=TRUE))");
+
+        assertEval("{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list()); bar(a=1,b=2,c=3); }");
+        assertEval("{ foo <- function() ls(parent.frame()); bar <- function(a,b,c) do.call('foo', list(), envir=globalenv()); bar(a=1,b=2,c=3) }");
+        assertEval("{ foo <- function(a,b)  list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a,b), env=e); }");
+        assertEval("{ foo <- function(a,b)  list(a=a,b=b); e <- new.env(); assign('a', 2); assign('b', 3); a<-0; b<-1; do.call('foo', list(a=as.name('a'),as.name('b')), env=e) }");
+        assertEval("{ foo <- function(a,b,c) { cat('foo called.'); list(a=a,b=b,c=c); }; side <- function() { cat('side effect!'); 42 }; do.call('foo', list(parse(text='side()')[[1]], 0, 0)); }");
+
+        assertEval("{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e); }");
+        assertEval("{ e <- new.env(); assign('a', 42, e); a <- 1; foo <- function(x) force(x); do.call('foo', list(as.name('a')), envir=e, quote=T); }");
+        assertEval("{ e <- new.env(); assign('foo', function() 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); }");
+        assertEval("{ e <- new.env(); assign('foo', 42, e); foo <- function(x) 1; do.call('foo', list(), envir=e); }");
+        assertEval("{ do.call('+', list(data.frame(1), data.frame(2)), envir = new.env()); do.call('assign', list('a',2,new.env()), envir = new.env()); }");
     }
 }