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 b137ce93957a49ff12bbb77f5edd43164f3ef873..ae7d5fc90258c04d53ef0a6fb87e310411e355b3 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
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -35,6 +35,8 @@ import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RArguments.DispatchArgs;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RVisibility;
+import com.oracle.truffle.r.runtime.builtins.FastPathFactory;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.REmpty;
@@ -42,6 +44,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.RFastPathNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 
 public abstract class CallMatcherNode extends RBaseNode {
@@ -198,6 +201,8 @@ public abstract class CallMatcherNode extends RBaseNode {
         @CompilationFinal private final long[] preparePermutation;
         private final MatchPermutation permutation;
         private final FormalArguments formals;
+        @Child private RFastPathNode fastPath;
+        private final RVisibility fastPathVisibility;
 
         CallMatcherCachedNode(ArgumentsSignature suppliedSignature, ArgumentsSignature[] varArgSignatures, RFunction function, long[] preparePermutation, MatchPermutation permutation,
                         boolean argsAreEvaluated, CallMatcherNode next) {
@@ -208,15 +213,21 @@ public abstract class CallMatcherNode extends RBaseNode {
             this.preparePermutation = preparePermutation;
             this.permutation = permutation;
             this.next = next;
-            this.formals = ((RRootNode) cachedFunction.getRootNode()).getFormalArguments();
+            RRootNode root = (RRootNode) cachedFunction.getRootNode();
+            this.formals = root.getFormalArguments();
             if (function.isBuiltin()) {
                 this.builtinDescriptor = function.getRBuiltin();
                 this.builtin = RBuiltinNode.inline(builtinDescriptor);
                 this.builtinArgumentCasts = builtin.getCasts();
+                this.fastPath = null;
+                this.fastPathVisibility = null;
             } else {
                 this.call = CallRFunctionNode.create(function.getTarget());
                 this.builtinArgumentCasts = null;
                 this.builtinDescriptor = null;
+                FastPathFactory fastPathFactory = root.getFastPath();
+                this.fastPath = fastPathFactory == null ? null : fastPathFactory.create();
+                this.fastPathVisibility = fastPathFactory == null ? null : fastPathFactory.getVisibility();
             }
         }
 
@@ -236,6 +247,17 @@ public abstract class CallMatcherNode extends RBaseNode {
                 Object[] reorderedArgs = matchedArgs.getArguments();
                 evaluatePromises(frame, cachedFunction, reorderedArgs, formals.getSignature().getVarArgIndex());
                 if (call != null) {
+                    if (fastPath != null) {
+                        Object result = fastPath.execute(frame, reorderedArgs);
+                        if (result != null) {
+                            assert fastPathVisibility != null;
+                            visibility.execute(frame, fastPathVisibility);
+                            return result;
+                        }
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        fastPath = null;
+                    }
+
                     RCaller parent = RArguments.getCall(frame).getParent();
                     String genFunctionName = functionName == null ? function.getName() : functionName;
                     Supplier<RSyntaxElement> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature);