diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
index eeb128e52496fcb2e675abefb2d681232b98d69b..764a1ba351c8f9e6b5763a9f4100871b34ef5e04 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quote.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.function.signature.QuoteNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.Closure;
 import com.oracle.truffle.r.runtime.data.RMissing;
@@ -37,6 +38,9 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 
+/**
+ * This builtin is just a fallback - this normally uses {@link QuoteNode} directly.
+ */
 @RBuiltin(name = "quote", nonEvalArgs = 0, kind = PRIMITIVE, parameterNames = {"expr"}, behavior = PURE)
 public abstract class Quote extends RBuiltinNode.Arg1 {
 
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 9f6f6652e1d19533b225ea5e3afe6c2943211587..1014eddf6e1e6af5fc16a37a4369a4a34b11a1cb 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
@@ -50,6 +50,7 @@ import com.oracle.truffle.r.nodes.function.RCallSpecialNode;
 import com.oracle.truffle.r.nodes.function.SaveArgumentsNode;
 import com.oracle.truffle.r.nodes.function.WrapDefaultArgumentNode;
 import com.oracle.truffle.r.nodes.function.signature.MissingNode;
+import com.oracle.truffle.r.nodes.function.signature.QuoteNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -142,6 +143,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 "quote":
+                    return new QuoteNode(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/function/signature/QuoteNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/QuoteNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..e31189acbce09dff4d85de5f6e705448f79bc4a1
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/signature/QuoteNode.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.function.signature;
+
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.nodes.RASTUtils;
+import com.oracle.truffle.r.nodes.control.OperatorNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.RError.Message;
+import com.oracle.truffle.r.runtime.data.RSymbol;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
+
+public final class QuoteNode extends OperatorNode {
+
+    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+
+    private final ArgumentsSignature signature;
+    private final RSyntaxElement[] args;
+
+    @CompilationFinal private Object value;
+
+    public QuoteNode(SourceSection source, RSyntaxLookup operator, ArgumentsSignature signature, RSyntaxElement[] args) {
+        super(source, operator);
+        this.signature = signature;
+        this.args = args;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        if (value == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            if (args.length != 1) {
+                throw error(Message.ARGUMENTS_PASSED, args.length, "'missing'", 1);
+            }
+            String name = signature.getName(0);
+            if (name != null && !name.isEmpty() && !"expr".equals(name)) {
+                throw error(Message.ARGUMENT_NOT_MATCH, name, "expr");
+            }
+            value = args[0] == null ? RSymbol.MISSING : RASTUtils.createLanguageElement(args[0]);
+        }
+        visibility.execute(frame, true);
+        return value;
+    }
+
+    @Override
+    public ArgumentsSignature getSyntaxSignature() {
+        return signature;
+    }
+
+    @Override
+    public RSyntaxElement[] getSyntaxArguments() {
+        return args;
+    }
+}