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 dbcf174805a15697847c63c09643e27572a98e02..746a892680cd7f6674d955dd2c501a1d1b290e4c 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
@@ -24,12 +24,13 @@ package com.oracle.truffle.r.nodes.builtin.base;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+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 static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.MaterializedFrame;
@@ -37,9 +38,11 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.FrameSlotNode;
+import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.builtin.base.GetFunctions.Get;
 import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen;
 import com.oracle.truffle.r.nodes.function.GetCallerFrameNode;
 import com.oracle.truffle.r.nodes.function.RCallBaseNode;
@@ -47,8 +50,10 @@ import com.oracle.truffle.r.nodes.function.RCallNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 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.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -56,21 +61,22 @@ import com.oracle.truffle.r.runtime.data.REmpty;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.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.nodes.InternalRSyntaxNodeChildren;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 // TODO Implement completely, this is a simple implementation that works when the envir argument is ignored
-@RBuiltin(name = "do.call", visibility = CUSTOM, kind = INTERNAL, parameterNames = {"what", "args", "envir"}, behavior = COMPLEX)
+@RBuiltin(name = "do.call", visibility = CUSTOM, kind = RBuiltinKind.SUBSTITUTE, parameterNames = {"what", "args", "quote", "envir"}, behavior = COMPLEX)
 public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNodeChildren {
 
-    @Child private GetFunctions.Get getNode;
     @Child private GetCallerFrameNode getCallerFrame;
     @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create();
 
@@ -85,30 +91,52 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
     protected void createCasts(CastBuilder casts) {
         casts.arg("what").defaultError(Message.MUST_BE_STRING_OR_FUNCTION, "what").mustBe(instanceOf(RFunction.class).or(stringValue()));
         casts.arg("args").mustBe(RAbstractListVector.class, Message.SECOND_ARGUMENT_LIST);
-        casts.arg("envir").mustBe(REnvironment.class, Message.MUST_BE_ENVIRON, "envir");
+        casts.arg("quote").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean());
+        casts.arg("envir").allowMissing().mustBe(REnvironment.class, Message.MUST_BE_ENVIRON, "envir");
     }
 
-    @Specialization
-    protected Object doCall(VirtualFrame frame, String what, RList argsAsList, REnvironment env) {
-        RFunction func;
-        if (getNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            getNode = insert(GetNodeGen.create());
+    protected static Get createGet() {
+        return GetNodeGen.create();
+    }
+
+    protected ReadVariableNode createRead(RAbstractStringVector what) {
+        if (what.getLength() != 1) {
+            CompilerDirectives.transferToInterpreter();
+            throw RError.error(this, RError.Message.MUST_BE_STRING_OR_FUNCTION, "what");
         }
-        func = (RFunction) getNode.execute(frame, what, env, RType.Function.getName(), true);
-        return doCall(frame, func, argsAsList, env);
+        return ReadVariableNode.createForcedFunctionLookup(RSyntaxNode.INTERNAL, what.getDataAt(0));
     }
 
     @Specialization
-    protected Object doCall(VirtualFrame frame, RStringVector what, RList argsAsList, REnvironment env) {
+    protected Object doCall(VirtualFrame frame, RAbstractStringVector what, RList argsAsList, boolean quote, REnvironment env,
+                    @Cached("createGet()") Get getNode) {
+        if (what.getLength() != 1) {
+            CompilerDirectives.transferToInterpreter();
+            throw RError.error(this, RError.Message.MUST_BE_STRING_OR_FUNCTION, "what");
+        }
+        RFunction func = (RFunction) getNode.execute(frame, what.getDataAt(0), env, RType.Function.getName(), true);
+        return doCall(frame, func, argsAsList, quote, env);
+    }
+
+    @Specialization(limit = "3", guards = {"what.getLength() == 1", "read.getIdentifier() == what.getDataAt(0)"})
+    protected Object doCallCached(VirtualFrame frame, @SuppressWarnings("unused") RAbstractStringVector what, RList argsAsList, boolean quote, RMissing env,
+                    @Cached("createRead(what)") ReadVariableNode read) {
+        RFunction func = (RFunction) read.execute(frame);
+        return doCall(frame, func, argsAsList, quote, env);
+    }
+
+    @Specialization(contains = "doCallCached")
+    protected Object doCall(VirtualFrame frame, RAbstractStringVector what, RList argsAsList, boolean quote, RMissing env) {
         if (what.getLength() != 1) {
+            CompilerDirectives.transferToInterpreter();
             throw RError.error(this, RError.Message.MUST_BE_STRING_OR_FUNCTION, "what");
         }
-        return doCall(frame, what.getDataAt(0), argsAsList, env);
+        RFunction func = ReadVariableNode.lookupFunction(what.getDataAt(0), frame.materialize());
+        return doCall(frame, func, argsAsList, quote, env);
     }
 
     @Specialization
-    protected Object doCall(VirtualFrame frame, RFunction func, RList argsAsList, @SuppressWarnings("unused") REnvironment env) {
+    protected Object doCall(VirtualFrame frame, RFunction func, RList argsAsList, boolean quote, @SuppressWarnings("unused") Object env) {
         /*
          * To re-create the illusion of a normal call, turn the values in argsAsList into promises.
          */
@@ -125,22 +153,21 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
             }
             signature = ArgumentsSignature.get(argNames);
         }
-        MaterializedFrame callerFrame = null;
-        for (int i = 0; i < argValues.length; i++) {
-            Object arg = argValues[i];
-            if (arg instanceof RLanguage) {
-                containsRLanguageProfile.enter();
-                callerFrame = getCallerFrame(frame, callerFrame);
-                RLanguage lang = (RLanguage) arg;
-                argValues[i] = createRLanguagePromise(callerFrame, lang);
-            } else if (arg instanceof RSymbol) {
-                containsRSymbolProfile.enter();
-                RSymbol symbol = (RSymbol) arg;
-                if (symbol.getName().isEmpty()) {
-                    argValues[i] = REmpty.instance;
-                } else {
-                    callerFrame = getCallerFrame(frame, callerFrame);
-                    argValues[i] = createLookupPromise(callerFrame, symbol);
+        if (!quote) {
+            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(frame.materialize(), lang);
+                } else if (arg instanceof RSymbol) {
+                    containsRSymbolProfile.enter();
+                    RSymbol symbol = (RSymbol) arg;
+                    if (symbol.getName().isEmpty()) {
+                        argValues[i] = REmpty.instance;
+                    } else {
+                        argValues[i] = createLookupPromise(frame.materialize(), symbol);
+                    }
                 }
             }
         }
@@ -163,16 +190,4 @@ public abstract class DoCall extends RBuiltinNode implements InternalRSyntaxNode
     private static RPromise createRLanguagePromise(MaterializedFrame callerFrame, RLanguage lang) {
         return RDataFactory.createPromise(PromiseState.Supplied, RPromise.Closure.create(RASTUtils.cloneNode(lang.getRep())), callerFrame);
     }
-
-    private MaterializedFrame getCallerFrame(VirtualFrame frame, MaterializedFrame callerFrame) {
-        if (getCallerFrame == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            getCallerFrame = insert(new GetCallerFrameNode());
-        }
-        if (callerFrame == null) {
-            return getCallerFrame.execute(frame);
-        } else {
-            return callerFrame;
-        }
-    }
 }
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 8ceadd73e895f2be154390df61a544787cf96a18..52cdce96c0f091dc3124305c828f088c226c6bd1 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
@@ -18702,6 +18702,14 @@ NULL
 #argv <- structure(list(expr = expression(quote(x <- c(1, x)))),     .Names = 'expr');do.call('.doTrace', argv)
 NULL
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#Output.IgnoreErrorContext#
+#typeof(do.call(function(x) x, list(as.symbol('foo'))))
+Error in (function (x)  : object 'foo' not found
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
+#typeof(do.call(function(x) x, list(as.symbol('foo')), quote=TRUE))
+[1] "symbol"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_docall.testDoCall#
 #v1 <- as.numeric_version('3.0.0'); v2 <- as.numeric_version('3.1.0'); do.call('<', list(quote(v1), quote(v2)))
 [1] TRUE
@@ -50617,13 +50625,9 @@ foo.bar(y, 42)
 foo.bar(y, 42)
 
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_syscall.testSysCall#
-#{ x<-do.call(function() sys.call(0), list()); x[[1]] }
-function() sys.call(0)
-
-##com.oracle.truffle.r.test.builtins.TestBuiltin_syscall.testSysCall#
-#{ x<-do.call(function() sys.call(1), list()); list(x[[1]], x[[2]][[1]], x[[2]][[2]], x[[2]][[3]]) }
+#{ x<-(function(f) f())(function() sys.call(1)); list(x[[1]], x[[2]][[1]], x[[2]][[2]], x[[2]][[3]]) }
 [[1]]
-do.call
+(function(f) f())
 
 [[2]]
 `function`
@@ -50635,6 +50639,10 @@ NULL
 sys.call(1)
 
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_syscall.testSysCall#
+#{ x<-do.call(function() sys.call(0), list()); x[[1]] }
+function() sys.call(0)
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_syscalls.testSysCalls#
 #sys.calls()
 NULL
@@ -54772,11 +54780,6 @@ NULL
 #argv <- list('raw', 0L); .Internal(vector(argv[[1]], argv[[2]]))
 raw(0)
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_warning.testwarning#
-#argv <- list('foo'); do.call('warning', argv)
-Warning message:
-In do.call("warning", argv) : foo
-
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_warning.testwarning#
 #f <- function() warning('foo'); f()
 Warning message:
@@ -54787,6 +54790,11 @@ In f() : foo
 Warning message:
 In f() : foo
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_warning.testwarning#
+#warning('foo')
+Warning message:
+foo
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_weekdaysDate.testweekdaysDate1#
 #argv <- structure(list(x = structure(16352, class = 'Date')),     .Names = 'x');do.call('weekdays.Date', argv)
 [1] "Thursday"
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 7f13a13bc2f4c91616bbfce1fad3e28de2933bdd..73fbac9e68fd11f22099a70addf59940d87cd915 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
@@ -29,5 +29,7 @@ public class TestBuiltin_docall extends TestBase {
         assertEval("{ do.call(\"+\", list(quote(1), 2))}");
         assertEval("v1 <- as.numeric_version('3.0.0'); v2 <- as.numeric_version('3.1.0'); do.call('<', list(v1, v2))");
         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))");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_syscall.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_syscall.java
index d080a5666e064ce1e05208b78ee7d615cd7f4d90..54d6ce721f9d5d609956d7a6427022ceaf546596 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_syscall.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_syscall.java
@@ -50,8 +50,8 @@ public class TestBuiltin_syscall extends TestBase {
         // these tests look a little weird as we seem to have some printing problems with language
         // objects (we should be able to simply print x, but the outputs don't quite match)
         assertEval("{ x<-do.call(function() sys.call(0), list()); x[[1]] }");
-        assertEval("{ x<-do.call(function() sys.call(1), list()); list(x[[1]], x[[2]][[1]], x[[2]][[2]], x[[2]][[3]]) }");
 
+        // whitespace in formatting of deparsed function
+        assertEval(Output.IgnoreWhitespace, "{ x<-(function(f) f())(function() sys.call(1)); list(x[[1]], x[[2]][[1]], x[[2]][[2]], x[[2]][[3]]) }");
     }
-
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_warning.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_warning.java
index 5a5983658c5f28085de17f339f515b5c38ebc13e..32105348fa57130763f66c036128cdf7a7b1df13 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_warning.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_warning.java
@@ -20,7 +20,7 @@ public class TestBuiltin_warning extends TestBase {
 
     @Test
     public void testwarning() {
-        assertEval("argv <- list('foo'); do.call('warning', argv)");
+        assertEval("warning('foo')");
         assertEval("f <- function() warning('foo'); f()");
         assertEval("f <- function() warning('foo'); f2 <- function() f(); f2()");
     }