From dd852367b3fd02015b9583445c99a158d3911db4 Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Thu, 21 Sep 2017 19:01:00 +0200
Subject: [PATCH] Materializing containers for '.Call'.

---
 .../foreign/CallAndExternalFunctions.java     | 30 ++++++++++------
 .../r/nodes/helpers/MaterializeNode.java      | 36 +++++++++++++++++++
 2 files changed, 56 insertions(+), 10 deletions(-)
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/MaterializeNode.java

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
index dd8bc94b7a..bdef66450b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java
@@ -71,6 +71,7 @@ import com.oracle.truffle.r.library.utils.TypeConvertNodeGen;
 import com.oracle.truffle.r.library.utils.UnzipNodeGen;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RInternalCodeBuiltinNode;
+import com.oracle.truffle.r.nodes.helpers.MaterializeNode;
 import com.oracle.truffle.r.nodes.objects.GetPrimNameNodeGen;
 import com.oracle.truffle.r.nodes.objects.NewObjectNodeGen;
 import com.oracle.truffle.r.runtime.FastROptions;
@@ -223,6 +224,7 @@ public class CallAndExternalFunctions {
     public abstract static class DotCall extends LookupAdapter {
 
         @Child CallRFFI.InvokeCallNode callRFFINode = RFFIFactory.getCallRFFI().createInvokeCallNode();
+        @Child MaterializeNode materializeNode = MaterializeNode.create();
 
         static {
             Casts.noCasts(DotCall.class);
@@ -233,6 +235,14 @@ public class CallAndExternalFunctions {
             return new Object[]{RMissing.instance, RArgsValuesAndNames.EMPTY, RMissing.instance};
         }
 
+        private Object[] materializeArgs(VirtualFrame frame, Object[] args) {
+            Object[] materializedArgs = new Object[args.length];
+            for (int i = 0; i < args.length; i++) {
+                materializedArgs[i] = materializeNode.execute(frame, args[i]);
+            }
+            return materializedArgs;
+        }
+
         @Override
         @TruffleBoundary
         public RExternalBuiltinNode lookupBuiltin(RList symbol) {
@@ -655,12 +665,12 @@ public class CallAndExternalFunctions {
          */
         @SuppressWarnings("unused")
         @Specialization(limit = "2", guards = {"cached == symbol", "builtin == null"})
-        protected Object callNamedFunction(RList symbol, RArgsValuesAndNames args, Object packageName,
+        protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
                         @Cached("symbol") RList cached,
                         @Cached("lookupBuiltin(symbol)") RExternalBuiltinNode builtin,
                         @Cached("new()") ExtractNativeCallInfoNode extractSymbolInfo,
                         @Cached("extractSymbolInfo.execute(symbol)") NativeCallInfo nativeCallInfo) {
-            return callRFFINode.dispatch(nativeCallInfo, args.getArguments());
+            return callRFFINode.dispatch(nativeCallInfo, materializeArgs(frame, args.getArguments()));
         }
 
         /**
@@ -669,24 +679,24 @@ public class CallAndExternalFunctions {
          */
         @SuppressWarnings("unused")
         @Specialization(replaces = {"callNamedFunction", "doExternal"})
-        protected Object callNamedFunctionGeneric(RList symbol, RArgsValuesAndNames args, Object packageName,
+        protected Object callNamedFunctionGeneric(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName,
                         @Cached("new()") ExtractNativeCallInfoNode extractSymbolInfo) {
             RExternalBuiltinNode builtin = lookupBuiltin(symbol);
             if (builtin != null) {
                 throw RInternalError.shouldNotReachHere("Cache for .Calls with FastR reimplementation (lookupBuiltin(...) != null) exceeded the limit");
             }
             NativeCallInfo nativeCallInfo = extractSymbolInfo.execute(symbol);
-            return callRFFINode.dispatch(nativeCallInfo, args.getArguments());
+            return callRFFINode.dispatch(nativeCallInfo, materializeArgs(frame, args.getArguments()));
         }
 
         /**
          * {@code .NAME = string}, no package specified.
          */
         @Specialization
-        protected Object callNamedFunction(String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
+        protected Object callNamedFunction(VirtualFrame frame, String symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName,
                         @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns,
                         @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
-            return callNamedFunctionWithPackage(symbol, args, null, rns, findSymbolNode);
+            return callNamedFunctionWithPackage(frame, symbol, args, null, rns, findSymbolNode);
         }
 
         /**
@@ -694,19 +704,19 @@ public class CallAndExternalFunctions {
          * define that symbol.
          */
         @Specialization
-        protected Object callNamedFunctionWithPackage(String symbol, RArgsValuesAndNames args, String packageName,
+        protected Object callNamedFunctionWithPackage(VirtualFrame frame, String symbol, RArgsValuesAndNames args, String packageName,
                         @Cached("createRegisteredNativeSymbol(CallNST)") DLL.RegisteredNativeSymbol rns,
                         @Cached("create()") DLL.RFindSymbolNode findSymbolNode) {
             DLL.SymbolHandle func = findSymbolNode.execute(symbol, packageName, rns);
             if (func == DLL.SYMBOL_NOT_FOUND) {
                 throw error(RError.Message.SYMBOL_NOT_IN_TABLE, symbol, "Call", packageName);
             }
-            return callRFFINode.dispatch(new NativeCallInfo(symbol, func, rns.getDllInfo()), args.getArguments());
+            return callRFFINode.dispatch(new NativeCallInfo(symbol, func, rns.getDllInfo()), materializeArgs(frame, args.getArguments()));
         }
 
         @Specialization
-        protected Object callNamedFunctionWithPackage(RExternalPtr symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
-            return callRFFINode.dispatch(new NativeCallInfo("", symbol.getAddr(), null), args.getArguments());
+        protected Object callNamedFunctionWithPackage(VirtualFrame frame, RExternalPtr symbol, RArgsValuesAndNames args, @SuppressWarnings("unused") RMissing packageName) {
+            return callRFFINode.dispatch(new NativeCallInfo("", symbol.getAddr(), null), materializeArgs(frame, args.getArguments()));
         }
 
         @SuppressWarnings("unused")
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/MaterializeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/MaterializeNode.java
new file mode 100644
index 0000000000..ec7c9da1e4
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/MaterializeNode.java
@@ -0,0 +1,36 @@
+package com.oracle.truffle.r.nodes.helpers;
+
+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.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+
+public abstract class MaterializeNode extends Node {
+
+    protected static final int LIMIT = 10;
+
+    public abstract Object execute(VirtualFrame frame, Object arg);
+
+    @Specialization(limit = "LIMIT", guards = {"vec.getClass() == cachedClass"})
+    protected RAbstractContainer doAbstractContainerCached(RAbstractContainer vec,
+                    @SuppressWarnings("unused") @Cached("vec.getClass()") Class<?> cachedClass) {
+        return vec.materialize();
+    }
+
+    @Specialization(replaces = "doAbstractContainerCached")
+    protected RAbstractContainer doAbstractContainer(RAbstractContainer vec) {
+        return vec.materialize();
+    }
+
+    @Fallback
+    protected Object doGeneric(Object o) {
+        return o;
+    }
+
+    public static MaterializeNode create() {
+        return MaterializeNodeGen.create();
+    }
+
+}
-- 
GitLab