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