From 16b6f941ec40dea125ea30d276ba332155d5db9d Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Tue, 6 Jun 2017 13:46:26 +0200
Subject: [PATCH] slow path without deop for PrepareArguments

---
 .../nodes/function/call/PrepareArguments.java | 49 +++++++++++++++++--
 1 file changed, 44 insertions(+), 5 deletions(-)

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 554d2b2b0e..62c6f044fb 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);
         }
     }
 
-- 
GitLab