From f4f418c9f28188d0c80be56c28e6e08ff92354ee Mon Sep 17 00:00:00 2001 From: Lukas Stadler <lukas.stadler@oracle.com> Date: Mon, 26 Jun 2017 11:45:50 +0200 Subject: [PATCH] additional TO_NATIVE handlers, support c++ compilation for llvm, use node for ffi unwrap operation, convert scalars to vectors at native boundary, use proper nodes for interop messages --- .../truffle/r/engine/interop/RFunctionMR.java | 8 ++ .../truffle/r/engine/interop/RLanguageMR.java | 8 ++ .../truffle/r/engine/interop/RSymbolMR.java | 10 +++ .../ffi/impl/common/JavaUpCallsRFFIImpl.java | 20 ++++- .../truffle/r/ffi/impl/common/RFFIUtils.java | 10 ++- .../{TruffleUnwrap.java => UpCallUnwrap.java} | 51 +++++++++--- .../r/ffi/impl/interop/NativePointer.java | 1 - .../r/ffi/impl/interop/base/GlobResultMR.java | 4 +- .../impl/interop/base/ReadlinkResultMR.java | 4 +- .../ffi/impl/interop/base/StrtolResultMR.java | 4 +- .../ffi/impl/interop/base/UnameResultMR.java | 4 +- .../interop/pcre/CaptureNamesResultMR.java | 9 ++- .../impl/interop/pcre/CompileResultMR.java | 8 +- .../pkginit/SetDotSymbolValuesCallMR.java | 6 +- .../r/ffi/impl/llvm/TruffleLLVM_Call.java | 79 +++++++++++++++++-- .../truffle/r/ffi/processor/FFIProcessor.java | 17 ++-- .../nodes/builtin/base/DynLoadFunctions.java | 1 + .../r/nodes/function/ArgumentMatcher.java | 2 +- .../oracle/truffle/r/runtime/RDeparse.java | 8 +- .../com/oracle/truffle/r/runtime/RError.java | 1 + .../truffle/r/runtime/data/RLanguage.java | 6 +- .../com/oracle/truffle/r/runtime/ffi/DLL.java | 4 + .../truffle/r/runtime/gnur/SEXPTYPE.java | 12 ++- documentation/dev/truffle_llvm_ffi.md | 2 +- mx.fastr/mx_fastr_compile.py | 25 +++--- 25 files changed, 236 insertions(+), 68 deletions(-) rename com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/{TruffleUnwrap.java => UpCallUnwrap.java} (58%) diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java index 191e2ab1d1..027ad9d9dd 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java @@ -32,6 +32,7 @@ import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.nodes.function.RCallBaseNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; @@ -50,6 +51,13 @@ public class RFunctionMR { } } + @Resolve(message = "TO_NATIVE") + public abstract static class RFunctionToNativeNode extends Node { + protected Object access(RFunction receiver) { + return new NativePointer(receiver); + } + } + @Resolve(message = "EXECUTE") public abstract static class RFunctionExecuteNode extends Node { private static final FrameDescriptor emptyFrameDescriptor = FrameSlotChangeMonitor.initializeFunctionFrameDescriptor("<interop>", new FrameDescriptor("R interop frame")); diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java index 701d96249d..c0c338cfb7 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java @@ -30,6 +30,7 @@ import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; import com.oracle.truffle.r.runtime.data.RLanguage; @@ -60,6 +61,13 @@ public class RLanguageMR { } } + @Resolve(message = "TO_NATIVE") + public abstract static class RLanguageToNativeNode extends Node { + protected Object access(RLanguage receiver) { + return new NativePointer(receiver); + } + } + @Resolve(message = "READ") public abstract static class RLanguageReadNode extends Node { @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true); diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java index fcb0c4e66c..3c00139f86 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java @@ -24,12 +24,22 @@ package com.oracle.truffle.r.engine.interop; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.runtime.data.RSymbol; @MessageResolution(receiverType = RSymbol.class) public class RSymbolMR { + + @Resolve(message = "TO_NATIVE") + public abstract static class RSymbolToNativeNode extends Node { + protected Object access(RSymbol receiver) { + return new NativePointer(receiver); + } + } + @CanResolve public abstract static class RSymbolCheck extends Node { diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java index f1fd7172b7..c9a4c1e477 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java @@ -768,6 +768,24 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { return result; } + private static final Object processResult(Object value) { + if (value instanceof Integer) { + int v = (int) value; + return RDataFactory.createIntVector(new int[]{v}, RRuntime.isNA(v)); + } else if (value instanceof Double) { + double v = (double) value; + return RDataFactory.createDoubleVector(new double[]{v}, RRuntime.isNA(v)); + } else if (value instanceof Byte) { + byte v = (byte) value; + return RDataFactory.createLogicalVector(new byte[]{v}, RRuntime.isNA(v)); + } else if (value instanceof String) { + String v = (String) value; + return RDataFactory.createStringVector(new String[]{v}, RRuntime.isNA(v)); + } else { + return value; + } + } + @Override public Object Rf_eval(Object expr, Object env) { guarantee(env instanceof REnvironment); @@ -794,7 +812,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { // just return value result = expr; } - return result; + return processResult(result); } @Override diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java index eba39a0222..08bbe61e9e 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/RFFIUtils.java @@ -27,6 +27,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Path; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.ffi.impl.nodes.FFIUpCallRootNode; import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI; @@ -192,10 +193,12 @@ public class RFFIUtils { // Error handling static RuntimeException unimplemented() { + CompilerDirectives.transferToInterpreter(); return unimplemented(""); } static RuntimeException unimplemented(String message) { + CompilerDirectives.transferToInterpreter(); throw RInternalError.unimplemented(message); } @@ -205,15 +208,18 @@ public class RFFIUtils { static void guarantee(boolean condition, String message) { if (!condition) { + CompilerDirectives.transferToInterpreter(); unimplemented(message); } } public static <T> T guaranteeInstanceOf(Object x, Class<T> clazz) { if (x == null) { - guarantee(false, "unexpected type: null instead of " + clazz.getSimpleName()); + CompilerDirectives.transferToInterpreter(); + unimplemented("unexpected type: null instead of " + clazz.getSimpleName()); } else if (!clazz.isInstance(x)) { - guarantee(false, "unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of " + clazz.getSimpleName()); + CompilerDirectives.transferToInterpreter(); + unimplemented("unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of " + clazz.getSimpleName()); } return clazz.cast(x); } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TruffleUnwrap.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/UpCallUnwrap.java similarity index 58% rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TruffleUnwrap.java rename to com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/UpCallUnwrap.java index f26f5152db..feac93f6af 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TruffleUnwrap.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/UpCallUnwrap.java @@ -22,14 +22,25 @@ */ package com.oracle.truffle.r.ffi.impl.common; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.interop.java.JavaInterop; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RTruffleObject; import com.oracle.truffle.r.runtime.ffi.RFFIFactory; -public class TruffleUnwrap { +public final class UpCallUnwrap extends Node { + + @Child private Node isBoxed; + @Child private Node unbox; + private final BranchProfile nativePointerProfile = isLLVM() ? BranchProfile.create() : null; + /** * There are three possibilities as enumerated below. * <ul> @@ -44,25 +55,47 @@ public class TruffleUnwrap { * to do.</li> * </ul> */ - public static Object unwrap(Object x) { + public Object unwrap(Object x) { if (x instanceof RTruffleObject) { return x; } else if (x instanceof TruffleObject) { - Object r = JavaInterop.unbox((TruffleObject) x); - if (r == null) { + if (isBoxed == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + isBoxed = insert(Message.IS_BOXED.createNode()); + } + TruffleObject xTo = (TruffleObject) x; + if (ForeignAccess.sendIsBoxed(isBoxed, xTo)) { + if (unbox == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + unbox = insert(Message.UNBOX.createNode()); + } + try { + return ForeignAccess.sendUnbox(unbox, xTo); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e, "UNBOX message fails after IS_BOXED=true"); + } + } else { // didn't UNBOX or really was null (e.g. null String) - if (RFFIFactory.getType() == RFFIFactory.Type.LLVM) { - TruffleObject xto = (TruffleObject) x; - TruffleObject xtoObject = NativePointer.check(xto); + if (isLLVM()) { + nativePointerProfile.enter(); + TruffleObject xtoObject = checkNativePointer(xTo); if (xtoObject != null) { return xtoObject; } } + return x; } - return r; } else { return x; } } + private static boolean isLLVM() { + return RFFIFactory.getType() == RFFIFactory.Type.LLVM; + } + + @TruffleBoundary + private static TruffleObject checkNativePointer(TruffleObject xto) { + return NativePointer.check(xto); + } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointer.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointer.java index 46d4ce53d4..4202b55d79 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointer.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/NativePointer.java @@ -113,5 +113,4 @@ public class NativePointer implements TruffleObject { protected long asPointerImpl() { return System.identityHashCode(object); } - } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResultMR.java index 1f40f124dd..2c7d26e85e 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResultMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/GlobResultMR.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.ffi.impl.interop.base; -import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; @@ -48,10 +47,9 @@ public class GlobResultMR { @Resolve(message = "EXECUTE") public abstract static class BaseGlobResultCallbackExecute extends Node { - protected Object access(@SuppressWarnings("unused") VirtualFrame frame, GlobResult receiver, Object[] arguments) { + protected Object access(GlobResult receiver, Object[] arguments) { receiver.addPath((String) arguments[0]); return receiver; } } - } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResultMR.java index 59af7efb20..56d518440a 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResultMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ReadlinkResultMR.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.ffi.impl.interop.base; -import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; @@ -48,10 +47,9 @@ public class ReadlinkResultMR { @Resolve(message = "EXECUTE") public abstract static class BaseReadlinkResultCallbackExecute extends Node { - protected Object access(@SuppressWarnings("unused") VirtualFrame frame, ReadlinkResult receiver, Object[] arguments) { + protected Object access(ReadlinkResult receiver, Object[] arguments) { receiver.setResult((String) arguments[0], (int) arguments[1]); return receiver; } } - } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResultMR.java index 7f427019eb..0b30658738 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResultMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/StrtolResultMR.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.ffi.impl.interop.base; -import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; @@ -48,10 +47,9 @@ public class StrtolResultMR { @Resolve(message = "EXECUTE") public abstract static class BaseStrtolResultCallbackExecute extends Node { - protected Object access(@SuppressWarnings("unused") VirtualFrame frame, StrtolResult receiver, Object[] arguments) { + protected Object access(StrtolResult receiver, Object[] arguments) { receiver.setResult((long) arguments[0], (int) arguments[1]); return receiver; } } - } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResultMR.java index 49c62b47ce..e63607fbad 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResultMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/UnameResultMR.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.ffi.impl.interop.base; -import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; @@ -48,10 +47,9 @@ public class UnameResultMR { @Resolve(message = "EXECUTE") public abstract static class BaseUnameResultCallbackExecute extends Node { - protected Object access(@SuppressWarnings("unused") VirtualFrame frame, UnameResult receiver, Object[] arguments) { + protected Object access(UnameResult receiver, Object[] arguments) { receiver.setResult((String) arguments[0], (String) arguments[1], (String) arguments[2], (String) arguments[3], (String) arguments[4]); return receiver; } } - } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResultMR.java index 3b3f915183..c57a4ef1c2 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResultMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CaptureNamesResultMR.java @@ -31,6 +31,7 @@ import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.r.runtime.RInternalError; @MessageResolution(receiverType = CaptureNamesResult.class) @@ -52,14 +53,18 @@ public class CaptureNamesResultMR { @Resolve(message = "EXECUTE") public abstract static class CaptureNamesCallbackExecute extends Node { + + @Child private Node isNullNode = Message.IS_NULL.createNode(); + @Child private Node unboxNode = Message.UNBOX.createNode(); + protected Object access(@SuppressWarnings("unused") VirtualFrame frame, CaptureNamesResult receiver, Object[] arguments) { try { Object arg1 = arguments[1]; if (arg1 instanceof TruffleObject) { - if (ForeignAccess.sendIsNull(Message.IS_NULL.createNode(), (TruffleObject) arg1)) { + if (ForeignAccess.sendIsNull(isNullNode, (TruffleObject) arg1)) { arg1 = null; } else { - arg1 = ForeignAccess.sendUnbox(Message.UNBOX.createNode(), (TruffleObject) arg1); + arg1 = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) arg1); } } receiver.addName((int) arguments[0], (String) arg1); diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResultMR.java index 1c98d1a352..ec104be372 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResultMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pcre/CompileResultMR.java @@ -52,14 +52,18 @@ public class CompileResultMR { @Resolve(message = "EXECUTE") public abstract static class ResultCallbackExecute extends Node { + + @Child private Node isNullNode = Message.IS_NULL.createNode(); + @Child private Node unboxNode = Message.UNBOX.createNode(); + protected Object access(@SuppressWarnings("unused") VirtualFrame frame, CompileResult receiver, Object[] arguments) { try { Object arg1 = arguments[1]; if (arg1 instanceof TruffleObject) { - if (ForeignAccess.sendIsNull(Message.IS_NULL.createNode(), (TruffleObject) arg1)) { + if (ForeignAccess.sendIsNull(isNullNode, (TruffleObject) arg1)) { arg1 = null; } else { - arg1 = ForeignAccess.sendUnbox(Message.UNBOX.createNode(), (TruffleObject) arg1); + arg1 = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) arg1); } } receiver.set((long) arguments[0], (String) arg1, (int) arguments[2]); diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java index 7b9482207f..2af43470af 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/pkginit/SetDotSymbolValuesCallMR.java @@ -25,15 +25,17 @@ package com.oracle.truffle.r.ffi.impl.interop.pkginit; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.ffi.impl.common.TruffleUnwrap; +import com.oracle.truffle.r.ffi.impl.common.UpCallUnwrap; import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo; @MessageResolution(receiverType = SetDotSymbolValuesCall.class) public class SetDotSymbolValuesCallMR { @Resolve(message = "EXECUTE") public abstract static class SetDotSymbolValuesCallExecute extends Node { + @Child private UpCallUnwrap unwrap = new UpCallUnwrap(); + protected java.lang.Object access(SetDotSymbolValuesCall receiver, Object[] arguments) { - return receiver.pkgInitUpCalls.setDotSymbolValues((DLLInfo) arguments[0], (String) TruffleUnwrap.unwrap(arguments[1]), arguments[2], (int) arguments[3]); + return receiver.pkgInitUpCalls.setDotSymbolValues((DLLInfo) arguments[0], (String) unwrap.unwrap(arguments[1]), arguments[2], (int) arguments[3]); } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java index 692d85abf0..e1f80e8b46 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Call.java @@ -22,24 +22,32 @@ */ package com.oracle.truffle.r.ffi.impl.llvm; +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.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.ffi.impl.common.RFFIUtils; -import com.oracle.truffle.r.ffi.impl.common.TruffleUnwrap; +import com.oracle.truffle.r.ffi.impl.common.UpCallUnwrap; +import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_CallFactory.ToNativeNodeGen; import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_CallFactory.TruffleLLVM_InvokeCallNodeGen; import com.oracle.truffle.r.ffi.impl.llvm.upcalls.BytesToNativeCharArrayCall; import com.oracle.truffle.r.ffi.impl.llvm.upcalls.CharSXPToNativeArrayCall; import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks; import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI; import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextState; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RScalar; +import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.ffi.CallRFFI; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; @@ -137,33 +145,92 @@ final class TruffleLLVM_Call implements CallRFFI { } } + abstract static class ToNativeNode extends Node { + + public abstract Object execute(Object value); + + @Specialization + protected static Object convert(int value) { + return RDataFactory.createIntVector(new int[]{value}, RRuntime.isNA(value)); + } + + @Specialization + protected static Object convert(double value) { + return RDataFactory.createDoubleVector(new double[]{value}, RRuntime.isNA(value)); + } + + @Specialization + protected static Object convert(RVector<?> value) { + return value; + } + + @Specialization + protected static Object convert(RScalar value) { + return value; + } + + @Specialization + protected static Object convert(byte value) { + return RDataFactory.createLogicalVector(new byte[]{value}, RRuntime.isNA(value)); + } + + @Specialization + protected static Object convert(String value) { + return RDataFactory.createStringVector(new String[]{value}, RRuntime.isNA(value)); + } + + @Fallback + protected static Object convert(Object value) { + return value; + } + } + @ImportStatic({Message.class}) public abstract static class TruffleLLVM_InvokeCallNode extends InvokeCallNode { + + @Child private UpCallUnwrap unwrap; private final boolean isVoid; protected TruffleLLVM_InvokeCallNode(boolean isVoid) { this.isVoid = isVoid; + this.unwrap = isVoid ? null : new UpCallUnwrap(); + } + + protected static ToNativeNode[] createConvertNodes(int length) { + ToNativeNode[] result = new ToNativeNode[length]; + for (int i = 0; i < length; i++) { + result[i] = ToNativeNodeGen.create(); + } + return result; } @Specialization(guards = {"cachedNativeCallInfo.name.equals(nativeCallInfo.name)", "args.length == cachedArgCount"}) protected Object invokeCallCached(NativeCallInfo nativeCallInfo, Object[] args, @SuppressWarnings("unused") @Cached("nativeCallInfo") NativeCallInfo cachedNativeCallInfo, @SuppressWarnings("unused") @Cached("argCount(args)") int cachedArgCount, - @Cached("createMessageNode(args)") Node cachedMessageNode) { - return doInvoke(cachedMessageNode, nativeCallInfo, args); + @Cached("createMessageNode(args)") Node cachedMessageNode, + @Cached("createConvertNodes(cachedArgCount)") ToNativeNode[] convert) { + return doInvoke(cachedMessageNode, nativeCallInfo, args, convert); } @Specialization(replaces = "invokeCallCached") + @TruffleBoundary protected Object invokeCallNormal(NativeCallInfo nativeCallInfo, Object[] args) { - return doInvoke(Message.createExecute(args.length).createNode(), nativeCallInfo, args); + return doInvoke(Message.createExecute(args.length).createNode(), nativeCallInfo, args, null); } - private Object doInvoke(Node messageNode, NativeCallInfo nativeCallInfo, Object[] args) { + @ExplodeLoop + private Object doInvoke(Node messageNode, NativeCallInfo nativeCallInfo, Object[] args, ToNativeNode[] convert) { boolean isNullSetting = RContext.getRForeignAccessFactory().setIsNull(false); try { + if (convert != null) { + for (int i = 0; i < convert.length; i++) { + args[i] = convert[i].execute(args[i]); + } + } Object result = ForeignAccess.sendExecute(messageNode, nativeCallInfo.address.asTruffleObject(), args); if (!isVoid) { - result = TruffleUnwrap.unwrap(result); + result = unwrap.unwrap(result); } return result; } catch (InteropException t) { diff --git a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java index b7614ecb6d..ed6a6b96dd 100644 --- a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java +++ b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java @@ -189,7 +189,6 @@ public final class FFIProcessor extends AbstractProcessor { w.append(" public ForeignAccess getForeignAccess() {\n"); w.append(" return ").append(callName).append("MRForeign.ACCESS;\n"); w.append(" }\n"); - w.append('\n'); w.append("}\n"); w.close(); } @@ -203,6 +202,7 @@ public final class FFIProcessor extends AbstractProcessor { StringBuilder arguments = new StringBuilder(); boolean usesUnwrap = false; + // process arguments first to see if unwrap is necessary int lparams = params.size(); for (int i = 0; i < lparams; i++) { String is = Integer.toString(i); @@ -214,7 +214,7 @@ public final class FFIProcessor extends AbstractProcessor { } if (isScalar) { usesUnwrap = true; - arguments.append("unwrap("); + arguments.append("unwrap.unwrap("); } arguments.append("arguments[").append(is).append("]"); if (isScalar) { @@ -229,19 +229,21 @@ public final class FFIProcessor extends AbstractProcessor { Writer w = fileObj.openWriter(); w.append("// GENERATED; DO NOT EDIT\n"); w.append("package ").append("com.oracle.truffle.r.ffi.impl.upcalls").append(";\n\n"); - if (usesUnwrap) { - w.append("import static com.oracle.truffle.r.ffi.impl.common.TruffleUnwrap.unwrap;\n"); - } w.append("import com.oracle.truffle.api.interop.MessageResolution;\n"); w.append("import com.oracle.truffle.api.interop.Resolve;\n"); w.append("import com.oracle.truffle.api.nodes.Node;\n"); - w.append("import com.oracle.truffle.r.ffi.impl.interop.NativePointer;\n"); + if (usesUnwrap) { + w.append("import com.oracle.truffle.r.ffi.impl.common.UpCallUnwrap;\n"); + } w.append("// Checkstyle: stop method name check\n\n"); w.append("@MessageResolution(receiverType = ").append(name).append("Call.class)\n"); w.append("public class ").append(callName).append("MR {\n"); w.append(" @Resolve(message = \"EXECUTE\")\n"); w.append(" public abstract static class ").append(callName).append("Execute extends Node {\n"); + if (usesUnwrap) { + w.append("\n @Child private UpCallUnwrap unwrap = new UpCallUnwrap();\n\n"); + } w.append(" protected ").append(returnType).append(" access(").append(callName).append(" receiver, "); if (params.size() == 0) { w.append("@SuppressWarnings(\"unused\") "); @@ -262,8 +264,6 @@ public final class FFIProcessor extends AbstractProcessor { w.append(" return true;\n"); w.append(" }\n"); w.append(" }\n"); - w.append("\n"); - w.append("}\n"); w.close(); @@ -386,5 +386,4 @@ public final class FFIProcessor extends AbstractProcessor { string.flush(); return e.getMessage() + "\r\n" + string.toString(); } - } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java index 1156a95d30..c871aa49bd 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java @@ -76,6 +76,7 @@ public class DynLoadFunctions { DLLInfo dllInfo = loadPackageDLLNode.execute(lib, local, now); return dllInfo.toRList(); } catch (DLLException ex) { + ex.printStackTrace(); throw error(ex); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java index e71f6f3450..9a43c2012e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java @@ -466,7 +466,7 @@ public class ArgumentMatcher { * method updates any wrapped ReadVariableNode to just return missing values without raising an * error. * - * @see com.oracle.truffle.r.nodes.function.PromiseNode.InlineVarArgsNode + * see {@code com.oracle.truffle.r.nodes.function.PromiseNode.InlineVarArgsNode} */ @SuppressWarnings("javadoc") private static RNode updateInlinedArg(RNode node) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java index 7eb1a77dd4..4ae8e1bc79 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java @@ -58,6 +58,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant; @@ -781,7 +782,12 @@ public class RDeparse { } append(')'); } else if (value instanceof RExternalPtr) { - append("<pointer: 0x").append(Long.toHexString(((RExternalPtr) value).getAddr().asAddress())).append('>'); + SymbolHandle handle = ((RExternalPtr) value).getAddr(); + if (handle.isLong()) { + append("<pointer: 0x").append(Long.toHexString(handle.asAddress())).append('>'); + } else { + append("<pointer: external ptr 0x").append(Long.toHexString(System.identityHashCode(handle.asTruffleObject()))).append('>'); + } } else if (value instanceof REnvironment) { append("<environment>"); } else if (value instanceof REmpty) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index 9311149b78..38b91d235c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -66,6 +66,7 @@ public final class RError extends RuntimeException implements TruffleException { private final RError.Message msg; @CompilationFinal(dimensions = 1) private final Object[] args; + @TruffleBoundary protected RErrorException(Throwable cause, RError.Message msg, Object[] args) { super(RErrorHandling.formatMessage(msg, args), cause); this.msg = msg; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java index 60e4849da5..aa46ff8da7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java @@ -47,7 +47,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode; * */ @ValueType -public class RLanguage extends RSharingAttributeStorage implements RAbstractContainer { +public final class RLanguage extends RSharingAttributeStorage implements RAbstractContainer { /* * Used for RLanguage construction from separate AST components. @@ -193,7 +193,7 @@ public class RLanguage extends RSharingAttributeStorage implements RAbstractCont } @Override - public final void setNames(RStringVector newNames) { + public void setNames(RStringVector newNames) { if (list == null) { /* See getNames */ RContext.getRRuntimeASTAccess().setNames(this, newNames); @@ -241,7 +241,7 @@ public class RLanguage extends RSharingAttributeStorage implements RAbstractCont return String.format("RLanguage(rep=%s)", getRep()); } - public final RPairList getPairListInternal() { + public RPairList getPairListInternal() { return this.list; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java index a0e0619811..f690726257 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java @@ -366,6 +366,10 @@ public class DLL { } } + public boolean isLong() { + return value instanceof Long; + } + public TruffleObject asTruffleObject() { if (value instanceof TruffleObject) { return (TruffleObject) value; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java index 9aa6e79d34..146301963b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java @@ -11,9 +11,6 @@ */ package com.oracle.truffle.r.runtime.gnur; -import java.util.HashMap; -import java.util.Map; - import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RComplex; @@ -98,21 +95,22 @@ public enum SEXPTYPE { public final int code; public final Class<?>[] fastRClasses; + private static final SEXPTYPE[] codeMap = new SEXPTYPE[501]; + SEXPTYPE(int code, Class<?>... fastRClasses) { this.code = code; this.fastRClasses = fastRClasses; } - private static final Map<Integer, SEXPTYPE> codeMap = new HashMap<>(); - static { for (SEXPTYPE type : SEXPTYPE.values()) { - SEXPTYPE.codeMap.put(type.code, type); + assert type.code >= 0 && type.code < codeMap.length; + codeMap[type.code] = type; } } public static SEXPTYPE mapInt(int type) { - return codeMap.get(type); + return codeMap[type]; } /** diff --git a/documentation/dev/truffle_llvm_ffi.md b/documentation/dev/truffle_llvm_ffi.md index 59e06668ff..0ae668fb01 100644 --- a/documentation/dev/truffle_llvm_ffi.md +++ b/documentation/dev/truffle_llvm_ffi.md @@ -18,7 +18,7 @@ On Mac OS, these can be installed with MacPorts (recommended) or Brew. Having in The above definitions assume a MacPorts installation. -On Linux, the installation is system dependent, but once installed, set the same environment variables. +On Linux, the installation is system dependent, but once installed, set the same environment variables. ## Building Sulong The `sulong` repository must be cloned to a sibling directory of `fastr` and built: diff --git a/mx.fastr/mx_fastr_compile.py b/mx.fastr/mx_fastr_compile.py index 11cc17e123..7619494a14 100644 --- a/mx.fastr/mx_fastr_compile.py +++ b/mx.fastr/mx_fastr_compile.py @@ -78,7 +78,7 @@ def _analyze_args(args, dragonEgg=False): Result is an instance of AnalyzedArgs: ''' compile_args = [] - emit_llvm_args = [] + emit_llvm_args = ['-g'] llvm_ir_file_ext = '.bc' if not dragonEgg: emit_llvm_args.append('-emit-llvm') @@ -171,15 +171,22 @@ def cpp(args): sulong = _sulong() if sulong: analyzed_args = _analyze_args(args) - if _is_linux(): - rc = sulong.dragonEggGPP(analyzed_args.compile_args) - elif _is_darwin(): - rc = sulong.compileWithClangPP(analyzed_args.compile_args) - if rc == 0: - if analyzed_args.llvm_ir_file: - rc = sulong.compileWithClangPP(analyzed_args.emit_llvm_args) + rc = 0 + if analyzed_args.is_link: + rc = _create_bc_lib(args) else: - mx.abort('unsupported platform') + if _is_linux(): + rc = sulong.dragonEggGPP(analyzed_args.compile_args) + elif _is_darwin(): + rc = sulong.compileWithClangPP(analyzed_args.compile_args) + if rc == 0: + if analyzed_args.llvm_ir_file: + rc = sulong.compileWithClangPP(analyzed_args.emit_llvm_args) + else: + mx.abort('unsupported platform') + if rc == 0 and not analyzed_args.is_link and analyzed_args.llvm_ir_file: + rc = _mem2reg_opt(analyzed_args.llvm_ir_file) + _fake_obj(analyzed_args.llvm_ir_file.replace('.bc', '.o')) else: compiler = 'g++' rc = mx.run([compiler] + args, nonZeroIsFatal=False) -- GitLab