From 0f362648ce34e3426bd11e7ff2feb96bd18cea4f Mon Sep 17 00:00:00 2001
From: stepan <stepan.sindelar@oracle.com>
Date: Tue, 20 Feb 2018 16:38:19 +0100
Subject: [PATCH] Serialize and push/pop callbacks for certain functions from
 NativeFunction

---
 .../llvm/TruffleLLVM_DownCallNodeFactory.java |  5 ++--
 .../managed/Managed_DownCallNodeFactory.java  |  6 ++--
 .../nfi/TruffleNFI_DownCallNodeFactory.java   | 14 ++++++++--
 .../fficall/src/truffle_common/base_rffi.c    |  8 ------
 .../fficall/src/truffle_nfi/Rembedded.c       | 17 ++++-------
 com.oracle.truffle.r.native/version.source    |  2 +-
 .../r/runtime/ffi/DownCallNodeFactory.java    | 15 ++++++----
 .../truffle/r/runtime/ffi/NativeFunction.java | 28 +++++++++++++++----
 8 files changed, 55 insertions(+), 40 deletions(-)

diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNodeFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNodeFactory.java
index 348720b931..722f0a242c 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNodeFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DownCallNodeFactory.java
@@ -69,7 +69,7 @@ final class TruffleLLVM_DownCallNodeFactory extends DownCallNodeFactory {
 
             @Override
             @ExplodeLoop
-            protected void wrapArguments(TruffleObject function, Object[] args) {
+            protected long beforeCall(NativeFunction nativeFunction, TruffleObject function, Object[] args) {
                 for (int i = 0; i < args.length; i++) {
                     Object obj = args[i];
                     if (obj instanceof double[]) {
@@ -82,6 +82,7 @@ final class TruffleLLVM_DownCallNodeFactory extends DownCallNodeFactory {
                         args[i] = new NativeCharArray(getStringBytes((String) obj));
                     }
                 }
+                return 0;
             }
 
             @TruffleBoundary
@@ -91,7 +92,7 @@ final class TruffleLLVM_DownCallNodeFactory extends DownCallNodeFactory {
 
             @Override
             @ExplodeLoop
-            protected void finishArguments(Object[] args) {
+            protected void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args) {
                 for (Object obj : args) {
                     if (obj instanceof NativeNACheck<?>) {
                         ((NativeNACheck<?>) obj).close();
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
index c30daa85b3..13eb6601ce 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_DownCallNodeFactory.java
@@ -70,7 +70,7 @@ public final class Managed_DownCallNodeFactory extends DownCallNodeFactory {
             }
 
             @Override
-            protected void wrapArguments(TruffleObject function, Object[] args) {
+            protected long beforeCall(NativeFunction nativeFunction, TruffleObject function, Object[] args) {
                 // Report unsupported functions at invocation time
                 if (function instanceof DummyFunctionObject) {
                     throw Managed_RFFIFactory.unsupported(((DummyFunctionObject) function).function.getCallName());
@@ -79,8 +79,8 @@ public final class Managed_DownCallNodeFactory extends DownCallNodeFactory {
             }
 
             @Override
-            protected void finishArguments(Object[] args) {
-                throw RInternalError.shouldNotReachHere();
+            protected void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args) {
+                // nop
             }
         };
     }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNodeFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNodeFactory.java
index efa57394f1..60eea1dfb8 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNodeFactory.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_DownCallNodeFactory.java
@@ -27,6 +27,7 @@ import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.r.ffi.impl.interop.NativeNACheck;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.ffi.DownCallNodeFactory;
 import com.oracle.truffle.r.runtime.ffi.NativeFunction;
 import com.oracle.truffle.r.runtime.ffi.interop.NativeUInt8Array;
@@ -49,7 +50,7 @@ public final class TruffleNFI_DownCallNodeFactory extends DownCallNodeFactory {
             @SuppressWarnings("cast")
             @Override
             @ExplodeLoop
-            protected void wrapArguments(TruffleObject function, Object[] args) {
+            protected long beforeCall(NativeFunction function, TruffleObject target, Object[] args) {
                 for (int i = 0; i < args.length; i++) {
                     Object obj = args[i];
                     if (obj instanceof double[]) {
@@ -71,6 +72,11 @@ public final class TruffleNFI_DownCallNodeFactory extends DownCallNodeFactory {
                         args[i] = JavaInterop.asTruffleObject(data);
                     }
                 }
+
+                if (function.hasComplexInteraction()) {
+                    return ((TruffleNFI_Context) RContext.getInstance().getRFFI()).beforeDowncall();
+                }
+                return 0;
             }
 
             @TruffleBoundary
@@ -83,7 +89,11 @@ public final class TruffleNFI_DownCallNodeFactory extends DownCallNodeFactory {
 
             @Override
             @ExplodeLoop
-            protected void finishArguments(Object[] args) {
+            protected void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args) {
+                if (function.hasComplexInteraction()) {
+                    RContext.getInstance().getRFFI().afterDowncall(before);
+                }
+
                 for (Object obj : args) {
                     // TODO: can this ever happen in NFI?
                     if (obj instanceof NativeNACheck<?>) {
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
index db79b2215b..73fc274caa 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
@@ -46,10 +46,6 @@ int call_base_chdir(char *dir) {
     return chdir(dir);
 }
 
-int call_base_mkdir(char *dir, int mode) {
-    return mkdir(dir, mode);
-}
-
 int call_base_mkdtemp(char *template) {
     char *r = mkdtemp(template);
     if (r == NULL) {
@@ -59,10 +55,6 @@ int call_base_mkdtemp(char *template) {
     }
 }
 
-int call_base_chmod(char *path, int mode) {
-    return chmod(path, mode);
-}
-
 void call_base_uname(void (*call_uname_setfields)(char *sysname, char *release, char *version, char *machine, char *nodename)) {
 	struct utsname name;
 
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
index 147982d7a0..21214ae229 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_nfi/Rembedded.c
@@ -503,23 +503,16 @@ void R_runHandlers(InputHandler *handlers, fd_set *mask) {
 
 // -----------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------
-// Downcalls from Java. We invoke these functions via .Call interface so that the callbacks
-// variable gets properly initialized and in general the R API is available. These functions
-// delegate to user provided C routines that may want to access the R API.
-// NOTE: those two functions are looked up by name!
+// Downcalls from Java. We invoke these functions via REmbedRFFI
 
-SEXP invokeCleanUp(SEXP x, SEXP y, SEXP z) {
-    ptr_R_CleanUp(Rf_asInteger(x), Rf_asInteger(y), Rf_asInteger(z));
-    return R_NilValue;
+void invokeCleanUp(int x, int y, int z) {
+    ptr_R_CleanUp(x, y, z);
 }
 
-SEXP invokeSuicide(SEXP msg) {
-    ptr_R_Suicide(R_CHAR(STRING_ELT(msg, 0)));
-    return R_NilValue;
+void invokeSuicide(char* msg) {
+    ptr_R_Suicide(msg);
 }
 
-// TODO: these 3 are not yet invoked via .Call
-
 void rembedded_write_console(char *cbuf, int len) {
     writeConsoleImpl(cbuf, len, 0);
 }
diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source
index 95f9650f01..e373ee695f 100644
--- a/com.oracle.truffle.r.native/version.source
+++ b/com.oracle.truffle.r.native/version.source
@@ -1 +1 @@
-49
+50
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DownCallNodeFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DownCallNodeFactory.java
index ad69b9cfe7..af484e9aee 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DownCallNodeFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DownCallNodeFactory.java
@@ -65,6 +65,7 @@ public abstract class DownCallNodeFactory {
          * NFI where the array should be passed as Java array, not as Truffle Object.
          */
         public final Object call(Object... args) {
+            long before = -1;
             try {
                 if (message == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -74,12 +75,12 @@ public abstract class DownCallNodeFactory {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
                     target = getTarget(function);
                 }
-                wrapArguments(target, args);
+                before = beforeCall(function, target, args);
                 return ForeignAccess.sendExecute(message, target, args);
             } catch (InteropException e) {
                 throw RInternalError.shouldNotReachHere(e);
             } finally {
-                finishArguments(args);
+                afterCall(before, function, target, args);
             }
         }
 
@@ -91,14 +92,16 @@ public abstract class DownCallNodeFactory {
 
         /**
          * Allows to transform the arguments before the execute message is sent to the result of
-         * {@link #getTarget(NativeFunction)}. Allways invoked even if {@code args.length == 0}.
+         * {@link #getTarget(NativeFunction)}.
          */
-        protected abstract void wrapArguments(TruffleObject function, Object[] args);
+        protected abstract long beforeCall(NativeFunction nativeFunction, TruffleObject function, Object[] args);
 
         /**
          * Allows to post-process the arguments after the execute message was sent to the result of
-         * {@link #getTarget(NativeFunction)}.
+         * {@link #getTarget(NativeFunction)}. If the call to
+         * {@link #beforeCall(NativeFunction, TruffleObject, Object[])} was not successfull, the
+         * {@code before} parameter will have value {@code -1}.
          */
-        protected abstract void finishArguments(Object[] args);
+        protected abstract void afterCall(long before, NativeFunction function, TruffleObject target, Object[] args);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
index ba0908f9ef..de1d47a0f6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
@@ -82,11 +82,11 @@ public enum NativeFunction {
     // FastR helpers
     set_exception_flag("(): void"),
     // FastR internal helper for R embedded mode
-    rembedded_write_console("(string, sint32):void"),
-    rembedded_write_err_console("(string, sint32):void"),
-    rembedded_read_console("(string):string"),
-    rembedded_native_clean_up("(sint32, sint32, sint32):void"),
-    rembedded_native_suicide("(string):void"),
+    rembedded_write_console("(string, sint32):void", "", anyLibrary(), true),
+    rembedded_write_err_console("(string, sint32):void", "", anyLibrary(), true),
+    rembedded_read_console("(string):string", "", anyLibrary(), true),
+    rembedded_native_clean_up("(sint32, sint32, sint32):void", "", anyLibrary(), true),
+    rembedded_native_suicide("(string):void", "", anyLibrary(), true),
     // user-defined RNG
     unif_init("(sint32): void", "user_", anyLibrary()),
     norm_rand("(): pointer", "user_", anyLibrary()),
@@ -94,6 +94,7 @@ public enum NativeFunction {
     unif_nseed("(): pointer", "user_", anyLibrary()),
     unif_seedloc("(): pointer", "user_", anyLibrary()),
     // memory access helper functions
+    // TODO: these could use Unsafe instead
     read_pointer_int("(pointer): sint32", "caccess_"),
     read_array_int("(pointer, sint64): sint32", "caccess_"),
     read_pointer_double("(pointer): double", "caccess_"),
@@ -109,12 +110,18 @@ public enum NativeFunction {
     private final String signature;
     private final int argumentCount;
     private final String library;
+    private final boolean complexInteraction;
 
-    NativeFunction(String signature, String prefix, String library) {
+    NativeFunction(String signature, String prefix, String library, boolean complexInteraction) {
         this.callName = prefix + name();
         this.signature = signature;
         this.argumentCount = getArgCount(signature);
         this.library = library;
+        this.complexInteraction = complexInteraction;
+    }
+
+    NativeFunction(String signature, String prefix, String library) {
+        this(signature, prefix, library, false);
     }
 
     NativeFunction(String signature, String prefix) {
@@ -141,6 +148,15 @@ public enum NativeFunction {
         return library;
     }
 
+    /**
+     * Returns {@code true} if the function has complex interaction with its environment, including
+     * that it is not reentrant, uses R API (e.g. {@code allocVector}), or may invoke arbitrary user
+     * code.
+     */
+    public boolean hasComplexInteraction() {
+        return complexInteraction;
+    }
+
     // Functions because the enum constants cannot refer to static final fields:
 
     public static String anyLibrary() {
-- 
GitLab