diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
index 554d2b2b0e16ba18889f4639f3bedf04492ec9e5..62c6f044fb95cda2d7c6063b6c7fda748e579bca 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
@@ -27,6 +27,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.nodes.Node;
@@ -38,11 +39,13 @@ import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.RCallNode;
 import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsDefaultNodeGen;
 import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsExplicitNodeGen;
+import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
 import com.oracle.truffle.r.runtime.Arguments;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
@@ -111,12 +114,48 @@ public abstract class PrepareArguments extends Node {
             return executeArgs(arguments.matchedArguments, arguments.matchedSuppliedSignature, frame);
         }
 
-        @Fallback
-        public RArgsValuesAndNames prepareGeneric(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call) {
-            CompilerDirectives.transferToInterpreter();
+        private static final class GenericCallEntry extends Node {
+            private final ArgumentsSignature cachedVarArgSignature;
+            private final S3DefaultArguments cachedS3DefaultArguments;
+
+            @Child private ArgumentsAndSignature arguments;
+
+            GenericCallEntry(ArgumentsSignature cachedVarArgSignature, S3DefaultArguments cachedS3DefaultArguments, ArgumentsAndSignature arguments) {
+                this.cachedVarArgSignature = cachedVarArgSignature;
+                this.cachedS3DefaultArguments = cachedS3DefaultArguments;
+                this.arguments = arguments;
+            }
+        }
+
+        /*
+         * Use a TruffleBoundaryNode to be able to switch child nodes without invalidating the whole
+         * method.
+         */
+        protected final class GenericCall extends TruffleBoundaryNode {
+
+            @Child private GenericCallEntry entry;
+
+            @TruffleBoundary
+            public RArgsValuesAndNames execute(MaterializedFrame materializedFrame, S3DefaultArguments s3DefaultArguments, ArgumentsSignature varArgSignature, RCallNode call) {
+                GenericCallEntry e = entry;
+                if (e == null || e.cachedVarArgSignature != varArgSignature || e.cachedS3DefaultArguments != s3DefaultArguments) {
+                    ArgumentsAndSignature arguments = createArguments(call, varArgSignature, s3DefaultArguments);
+                    entry = e = insert(new GenericCallEntry(varArgSignature, s3DefaultArguments, arguments));
+                }
+                VirtualFrame frame = SubstituteVirtualFrame.create(materializedFrame);
+                return executeArgs(e.arguments.matchedArguments, e.arguments.matchedSuppliedSignature, frame);
+            }
+        }
+
+        protected GenericCall createGenericCall() {
+            return new GenericCall();
+        }
+
+        @Specialization
+        public RArgsValuesAndNames prepareGeneric(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call,
+                        @Cached("createGenericCall()") GenericCall generic) {
             ArgumentsSignature varArgSignature = varArgs == null ? null : varArgs.getSignature();
-            Arguments<RNode> matchedArgs = ArgumentMatcher.matchArguments(target, sourceArguments, varArgSignature, s3DefaultArguments, RError.ROOTNODE, true);
-            return executeArgs(matchedArgs.getArguments(), matchedArgs.getSignature(), frame);
+            return generic.execute(frame.materialize(), s3DefaultArguments, varArgSignature, call);
         }
     }