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 f5c8657f51ecdfe30856f16a9da493aed3267cab..5c4f604aa5853122bbf3d7bc854efbebbe02b2de 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 @@ -35,32 +35,14 @@ import java.util.IdentityHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.MaterializedFrame; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.interop.ArityException; -import com.oracle.truffle.api.interop.CanResolve; -import com.oracle.truffle.api.interop.ForeignAccess; -import com.oracle.truffle.api.interop.ForeignAccess.StandardFactory; -import com.oracle.truffle.api.interop.Message; -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.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; -import com.oracle.truffle.api.interop.UnsupportedTypeException; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.ffi.impl.common.JavaUpCallsRFFIImplFactory.VectorWrapperNativePointerFactory.DispatchAllocateNodeGen; import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; @@ -122,9 +104,9 @@ import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.ffi.RFFIContext; import com.oracle.truffle.r.runtime.ffi.UnsafeAdapter; +import com.oracle.truffle.r.runtime.ffi.VectorRFFIWrapper; import com.oracle.truffle.r.runtime.gnur.SA_TYPE; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; -import com.oracle.truffle.r.runtime.nodes.DuplicationHelper; import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; import com.oracle.truffle.r.runtime.rng.RRNG; @@ -1375,10 +1357,10 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { return RConnection.fromIndex(fd); } - private static VectorWrapper wrapString(String s) { + private static VectorRFFIWrapper wrapString(String s) { CharSXPWrapper v = CharSXPWrapper.create(s); NativeDataAccess.asPointer(v); - return new VectorWrapper(v); + return VectorRFFIWrapper.get(v); } @Override @@ -2134,298 +2116,36 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { throw implementedAsNode(); } - public static class VectorWrapperNativePointer implements TruffleObject { - - private final TruffleObject vector; - - VectorWrapperNativePointer(TruffleObject vector) { - this.vector = vector; - assert vector instanceof RObject; - NativeDataAccess.asPointer(vector); // initialize the native mirror in the vector - } - - abstract static class InteropRootNode extends RootNode { - InteropRootNode() { - super(/* TruffleRLanguageImpl.getCurrentLanguage() */null); - } - - @Override - public final SourceSection getSourceSection() { - return RSyntaxNode.INTERNAL; - } - } - - // TODO: with separate version of this for the different types, it would be more efficient - // and not need the dispatch - public abstract static class DispatchAllocate extends Node { - private static final long EMPTY_DATA_ADDRESS = 0x1BAD; - - public abstract long execute(Object vector); - - @Specialization - @TruffleBoundary - protected static long get(RIntVector vector) { - return vector.allocateNativeContents(); - } - - @Specialization - @TruffleBoundary - protected static long get(RLogicalVector vector) { - return vector.allocateNativeContents(); - } - - @Specialization - @TruffleBoundary - protected static long get(RRawVector vector) { - return vector.allocateNativeContents(); - } - - @Specialization - @TruffleBoundary - protected static long get(RDoubleVector vector) { - return vector.allocateNativeContents(); - } - - @Specialization - @TruffleBoundary - protected static long get(RComplexVector vector) { - return vector.allocateNativeContents(); - } - - @Specialization - @TruffleBoundary - protected static long get(CharSXPWrapper vector) { - return vector.allocateNativeContents(); - } - - @Specialization - protected static long get(@SuppressWarnings("unused") RNull nullValue) { - // Note: GnuR is OK with, e.g., INTEGER(NULL), but it's illegal to read from or - // write to the resulting address. - return EMPTY_DATA_ADDRESS; - } - - @Fallback - protected static long get(Object vector) { - throw RInternalError.shouldNotReachHere("invalid wrapped object " + vector.getClass().getSimpleName()); - } - } - - @Override - public ForeignAccess getForeignAccess() { - return ForeignAccess.create(VectorWrapperNativePointer.class, new StandardFactory() { - @Override - public CallTarget accessIsNull() { - return Truffle.getRuntime().createCallTarget(new InteropRootNode() { - @Override - public Object execute(VirtualFrame frame) { - return false; - } - }); - } - - @Override - public CallTarget accessIsPointer() { - return Truffle.getRuntime().createCallTarget(new InteropRootNode() { - @Override - public Object execute(VirtualFrame frame) { - return true; - } - }); - } - - @Override - public CallTarget accessAsPointer() { - return Truffle.getRuntime().createCallTarget(new InteropRootNode() { - @Child private DispatchAllocate dispatch = DispatchAllocateNodeGen.create(); - - @Override - public Object execute(VirtualFrame frame) { - VectorWrapperNativePointer receiver = (VectorWrapperNativePointer) ForeignAccess.getReceiver(frame); - return dispatch.execute(receiver.vector); - } - }); - } - - @Override - public CallTarget accessToNative() { - return Truffle.getRuntime().createCallTarget(new InteropRootNode() { - @Override - public Object execute(VirtualFrame frame) { - return ForeignAccess.getReceiver(frame); - } - }); - } - }); - } - } - - @MessageResolution(receiverType = VectorWrapper.class) - public static class VectorWrapperMR { - - @Resolve(message = "IS_POINTER") - public abstract static class IntVectorWrapperNativeIsPointerNode extends Node { - protected Object access(@SuppressWarnings("unused") VectorWrapper receiver) { - return false; - } - } - - @Resolve(message = "TO_NATIVE") - public abstract static class IntVectorWrapperNativeAsPointerNode extends Node { - protected Object access(VectorWrapper receiver) { - return new VectorWrapperNativePointer(receiver.vector); - } - } - - @Resolve(message = "HAS_SIZE") - public abstract static class VectorWrapperHasSizeNode extends Node { - protected Object access(@SuppressWarnings("unused") VectorWrapper receiver) { - return true; - } - } - - @Resolve(message = "GET_SIZE") - public abstract static class VectorWrapperGetSizeNode extends Node { - @Child private Node getSizeMsg = Message.GET_SIZE.createNode(); - - protected Object access(VectorWrapper receiver) { - try { - return ForeignAccess.sendGetSize(getSizeMsg, receiver.vector); - } catch (UnsupportedMessageException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - } - - @Resolve(message = "READ") - abstract static class VectorWrapperReadNode extends Node { - @Child private Node readMsg = Message.READ.createNode(); - - public Object access(VectorWrapper receiver, Object index) { - try { - return ForeignAccess.sendRead(readMsg, receiver.vector, index); - } catch (UnsupportedMessageException | UnknownIdentifierException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - } - - @Resolve(message = "WRITE") - abstract static class VectorWrapperWriteNode extends Node { - @Child private Node writeMsg = Message.WRITE.createNode(); - - public Object access(VectorWrapper receiver, Object index, Object value) { - try { - return ForeignAccess.sendWrite(writeMsg, receiver.vector, index, value); - } catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - } - - @Resolve(message = "IS_EXECUTABLE") - abstract static class VectorWrapperIsExecutableNode extends Node { - @Child private Node isExecMsg = Message.IS_EXECUTABLE.createNode(); - - public Object access(VectorWrapper receiver) { - return ForeignAccess.sendIsExecutable(isExecMsg, receiver.vector); - } - } - - @Resolve(message = "EXECUTE") - abstract static class VectorWrapperExecuteNode extends Node { - @Child private Node execMsg = Message.createExecute(0).createNode(); - - protected Object access(VectorWrapper receiver, Object[] arguments) { - try { - // Currently, there is only one "executable" object, which is - // CharSXPWrapper. - // See CharSXPWrapperMR for the EXECUTABLE message handler. - assert arguments.length == 0 && receiver.vector instanceof CharSXPWrapper; - return ForeignAccess.sendExecute(execMsg, receiver.vector); - } catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - } - - @CanResolve - public abstract static class VectorWrapperCheck extends Node { - protected static boolean test(TruffleObject receiver) { - return receiver instanceof VectorWrapper; - } - } - } - - public static final class VectorWrapper implements TruffleObject { - - private final TruffleObject vector; - - public VectorWrapper(TruffleObject vector) { - assert vector instanceof RObject; - this.vector = vector; - NativeDataAccess.setNativeWrapper((RObject) vector, this); - } - - public static Object get(TruffleObject x) { - assert x instanceof RObject; - Object wrapper = NativeDataAccess.getNativeWrapper((RObject) x); - if (wrapper != null) { - return wrapper; - } else { - wrapper = new VectorWrapper(x); - // Establish the 1-1 relationship between the object and its native wrapper - NativeDataAccess.setNativeWrapper((RObject) x, wrapper); - return wrapper; - } - } - - public TruffleObject getVector() { - return vector; - } - - @Override - public ForeignAccess getForeignAccess() { - return VectorWrapperMRForeign.ACCESS; - } - - @Override - public int hashCode() { - return vector.hashCode(); - } - - } - @Override public Object INTEGER(Object x) { // also handles LOGICAL assert x instanceof RIntVector || x instanceof RLogicalVector || x == RNull.instance; - return VectorWrapper.get(guaranteeVectorOrNull(x, RVector.class)); + return VectorRFFIWrapper.get(guaranteeVectorOrNull(x, RVector.class)); } @Override public Object LOGICAL(Object x) { - return VectorWrapper.get(guaranteeVectorOrNull(x, RLogicalVector.class)); + return VectorRFFIWrapper.get(guaranteeVectorOrNull(x, RLogicalVector.class)); } @Override public Object REAL(Object x) { - return VectorWrapper.get(guaranteeVectorOrNull(x, RDoubleVector.class)); + return VectorRFFIWrapper.get(guaranteeVectorOrNull(x, RDoubleVector.class)); } @Override public Object RAW(Object x) { - return VectorWrapper.get(guaranteeVectorOrNull(x, RRawVector.class)); + return VectorRFFIWrapper.get(guaranteeVectorOrNull(x, RRawVector.class)); } @Override public Object COMPLEX(Object x) { - return VectorWrapper.get(guaranteeVectorOrNull(x, RComplexVector.class)); + return VectorRFFIWrapper.get(guaranteeVectorOrNull(x, RComplexVector.class)); } @Override public Object R_CHAR(Object x) { - return VectorWrapper.get(guaranteeVectorOrNull(x, CharSXPWrapper.class)); + return VectorRFFIWrapper.get(guaranteeVectorOrNull(x, CharSXPWrapper.class)); } @Override diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/DLLInfoMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/DLLInfoMR.java index 042dd55698dc94025ed00e6f0cfe957d1bbc8ee9..cf4ba863e7002c187e49249f1e5ea2a2b7cea22b 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/DLLInfoMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/DLLInfoMR.java @@ -27,9 +27,9 @@ 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.common.JavaUpCallsRFFIImpl.VectorWrapper; import com.oracle.truffle.r.runtime.data.CharSXPWrapper; import com.oracle.truffle.r.runtime.ffi.DLL; +import com.oracle.truffle.r.runtime.ffi.VectorRFFIWrapper; import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo; import com.oracle.truffle.r.runtime.interop.RObjectNativeWrapper; @@ -67,7 +67,7 @@ public class DLLInfoMR { throw new IndexOutOfBoundsException("Index can be 0 or 1"); } - return VectorWrapper.get(res); + return VectorRFFIWrapper.get(res); } } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/FFI_RForeignAccessFactoryImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/FFI_RForeignAccessFactoryImpl.java index 18e434a657ac449a53ff211d2adc5bedb54db0e6..9914b38c2c60ca6b3b92bd59cc177e42bb91b2ef 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/FFI_RForeignAccessFactoryImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/FFI_RForeignAccessFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ package com.oracle.truffle.r.ffi.impl.interop; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.r.runtime.data.CharSXPWrapper; +import com.oracle.truffle.r.runtime.data.CharSXPWrapperMRForeign; import com.oracle.truffle.r.runtime.data.RTruffleObject; import com.oracle.truffle.r.runtime.ffi.DLL; diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java index 496e75c66772ebe742fb085878293a364ae48a6e..d16b67adc421004bedc17cb2be3734b19c90060a 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_C.java @@ -22,66 +22,23 @@ */ package com.oracle.truffle.r.ffi.impl.llvm; -import com.oracle.truffle.api.CompilerDirectives; -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.Node; -import com.oracle.truffle.r.ffi.impl.interop.NativeDoubleArray; -import com.oracle.truffle.r.ffi.impl.interop.NativeIntegerArray; -import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.ffi.CRFFI; -import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; -import com.oracle.truffle.r.runtime.ffi.interop.NativeRawArray; +import com.oracle.truffle.r.runtime.ffi.InvokeCNode; +import com.oracle.truffle.r.runtime.ffi.InvokeCNode.FunctionObjectGetter; +import com.oracle.truffle.r.runtime.ffi.InvokeCNodeGen; -class TruffleLLVM_C implements CRFFI { - private static class TruffleLLVM_InvokeCNode extends InvokeCNode { - - @Child private Node messageNode; - private int numArgs; +public class TruffleLLVM_C implements CRFFI { + static final class LLVMFunctionObjectGetter extends FunctionObjectGetter { @Override - public void execute(NativeCallInfo nativeCallInfo, Object[] args) { - Object[] wargs = wrap(args); - try { - if (messageNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - // TODO: we assume that the number of args doesn't change, is that correct? - messageNode = Message.createExecute(args.length).createNode(); - numArgs = args.length; - } - assert numArgs == args.length; - ForeignAccess.sendExecute(messageNode, nativeCallInfo.address.asTruffleObject(), wargs); - } catch (InteropException ex) { - throw RInternalError.shouldNotReachHere(ex); - } - } - - Object[] wrap(Object[] args) { - Object[] nargs = new Object[args.length]; - for (int i = 0; i < args.length; i++) { - Object arg = args[i]; - Object narg; - if (arg instanceof int[]) { - narg = new NativeIntegerArray((int[]) arg); - } else if (arg instanceof double[]) { - narg = new NativeDoubleArray((double[]) arg); - } else if (arg instanceof byte[]) { - narg = new NativeRawArray((byte[]) arg); - } else if (arg instanceof TruffleObject) { - narg = arg; - } else { - throw RInternalError.unimplemented(".C type: " + arg.getClass().getSimpleName()); - } - nargs[i] = narg; - } - return nargs; + public TruffleObject execute(TruffleObject address, int arity) { + return address; } } @Override public InvokeCNode createInvokeCNode() { - return new TruffleLLVM_InvokeCNode(); + return InvokeCNodeGen.create(new LLVMFunctionObjectGetter()); } } 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 1fd55bb5d9ad254ce2f65de34be363e9c1144fc0..87103c060180052657726a1f72a0557451990ccb 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 @@ -40,7 +40,6 @@ import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_CallFactory.TruffleLLVM_In 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.FFIUnwrapNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; @@ -50,6 +49,7 @@ 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.FFIUnwrapNode; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; import com.oracle.truffle.r.runtime.ffi.RFFIFactory; @@ -189,7 +189,7 @@ final class TruffleLLVM_Call implements CallRFFI { @Specialization protected static Object convert(String value) { - return RDataFactory.createStringVectorFromScalar(value).makeSharedPermanent(); + return RDataFactory.createStringVectorFromScalar(value); } @Fallback diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java index ad6eed382d4b3c7322dc5fbefc3d4fddc11ec70c..f87a8d3676452ee4f87583e2093e471111de7817 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_UpCallsRFFIImpl.java @@ -30,7 +30,6 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.ffi.impl.common.JavaUpCallsRFFIImpl; import com.oracle.truffle.r.ffi.impl.common.RFFIUtils; import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks; -import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode; import com.oracle.truffle.r.runtime.REnvVars; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; @@ -43,9 +42,11 @@ import com.oracle.truffle.r.runtime.data.RScalar; import com.oracle.truffle.r.runtime.data.RString; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.ffi.DLL; +import com.oracle.truffle.r.runtime.ffi.FFIUnwrapNode; import com.oracle.truffle.r.runtime.ffi.DLL.CEntry; import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; +import com.oracle.truffle.r.runtime.ffi.VectorRFFIWrapper; import com.oracle.truffle.r.runtime.ffi.interop.NativeCharArray; /** @@ -74,8 +75,8 @@ public class TruffleLLVM_UpCallsRFFIImpl extends JavaUpCallsRFFIImpl { @Override public Object Rf_mkCharLenCE(Object obj, int len, int encoding) { - if (obj instanceof VectorWrapper) { - Object wrappedCharSXP = ((VectorWrapper) obj).getVector(); + if (obj instanceof VectorRFFIWrapper) { + Object wrappedCharSXP = ((VectorRFFIWrapper) obj).getVector(); assert wrappedCharSXP instanceof CharSXPWrapper; return wrappedCharSXP; } else if (obj instanceof NativeCharArray) { diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java index 3d32fdf2838e08d6b5e1c1c9bf0587a980b3d2c0..62cc7e662e7f66d008d1b35e60eef4836f32b078 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_RFFIFactory.java @@ -33,6 +33,7 @@ import com.oracle.truffle.r.runtime.ffi.CRFFI; import com.oracle.truffle.r.runtime.ffi.CallRFFI; import com.oracle.truffle.r.runtime.ffi.CallRFFI.HandleUpCallExceptionNode; import com.oracle.truffle.r.runtime.ffi.DLLRFFI; +import com.oracle.truffle.r.runtime.ffi.InvokeCNode; import com.oracle.truffle.r.runtime.ffi.LapackRFFI; import com.oracle.truffle.r.runtime.ffi.MiscRFFI; import com.oracle.truffle.r.runtime.ffi.NativeFunction; diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java index 7e34eee2870a947c70c3e7cc25559817341c6ad6..39b788f6c1c006a8b68071c47504b3f720a9cfb3 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_C.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,17 +24,16 @@ package com.oracle.truffle.r.ffi.impl.nfi; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Cached; -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.Node; -import com.oracle.truffle.r.ffi.impl.nfi.TruffleNFI_CFactory.TruffleNFI_InvokeCNodeGen; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.ffi.CRFFI; -import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; +import com.oracle.truffle.r.runtime.ffi.InvokeCNode; +import com.oracle.truffle.r.runtime.ffi.InvokeCNode.FunctionObjectGetter; +import com.oracle.truffle.r.runtime.ffi.InvokeCNodeGen; public class TruffleNFI_C implements CRFFI { @@ -58,51 +57,25 @@ public class TruffleNFI_C implements CRFFI { } } - abstract static class TruffleNFI_InvokeCNode extends InvokeCNode { + static final class NFIFunctionObjectGetter extends FunctionObjectGetter { @Child private Node bindNode = Message.createInvoke(1).createNode(); + @Override @TruffleBoundary - protected TruffleObject getFunction(TruffleObject address, int arity) { + public TruffleObject execute(TruffleObject address, int arity) { // cache signatures try { - return (TruffleObject) ForeignAccess.sendInvoke(bindNode, address, "bind", getSignatureForArity(arity)); + return (TruffleObject) ForeignAccess.sendInvoke(bindNode, address, "bind", + getSignatureForArity(arity)); } catch (InteropException ex) { throw RInternalError.shouldNotReachHere(ex); } } - - @Specialization(guards = {"args.length == cachedArgsLength", "nativeCallInfo.address.asTruffleObject() == cachedAddress"}) - protected void invokeCallCached(@SuppressWarnings("unused") NativeCallInfo nativeCallInfo, Object[] args, - @SuppressWarnings("unused") @Cached("args.length") int cachedArgsLength, - @Cached("createExecute(cachedArgsLength)") Node executeNode, - @SuppressWarnings("unused") @Cached("nativeCallInfo.address.asTruffleObject()") TruffleObject cachedAddress, - @Cached("getFunction(cachedAddress, cachedArgsLength)") TruffleObject cachedFunction) { - try { - ForeignAccess.sendExecute(executeNode, cachedFunction, args); - } catch (InteropException ex) { - throw RInternalError.shouldNotReachHere(ex); - } - } - - @Specialization(limit = "99", guards = "args.length == cachedArgsLength") - protected void invokeCallCachedLength(NativeCallInfo nativeCallInfo, Object[] args, - @Cached("args.length") int cachedArgsLength, - @Cached("createExecute(cachedArgsLength)") Node executeNode) { - try { - ForeignAccess.sendExecute(executeNode, getFunction(nativeCallInfo.address.asTruffleObject(), cachedArgsLength), args); - } catch (InteropException ex) { - throw RInternalError.shouldNotReachHere(ex); - } - } - - public static Node createExecute(int n) { - return Message.createExecute(n).createNode(); - } } @Override public InvokeCNode createInvokeCNode() { - return TruffleNFI_InvokeCNodeGen.create(); + return InvokeCNodeGen.create(new NFIFunctionObjectGetter()); } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java index 9489dea36533d1a22dcdc453ec77aa1c149709dc..eaeb8c8b05ff93e3a9e6b27eb7b730ed1e9d3734 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Call.java @@ -39,12 +39,12 @@ 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.nfi.TruffleNFI_CallFactory.TruffleNFI_InvokeCallNodeGen; -import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode; -import com.oracle.truffle.r.ffi.impl.upcalls.FFIWrapNode; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.ffi.CallRFFI; import com.oracle.truffle.r.runtime.ffi.DLL; +import com.oracle.truffle.r.runtime.ffi.FFIUnwrapNode; +import com.oracle.truffle.r.runtime.ffi.FFIWrapNode; import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; public class TruffleNFI_Call implements CallRFFI { diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java index 172709048798f52b635c2298d2c69dad62c5a602..4da8da75092db89e6e837082f67beaf5f0e7e007 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_UpCallsRFFIImpl.java @@ -30,12 +30,12 @@ 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.common.JavaUpCallsRFFIImpl; -import com.oracle.truffle.r.ffi.impl.upcalls.FFIUnwrapNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.CharSXPWrapper; import com.oracle.truffle.r.runtime.ffi.DLL; +import com.oracle.truffle.r.runtime.ffi.FFIUnwrapNode; import com.oracle.truffle.r.runtime.ffi.DLL.CEntry; import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo; import com.oracle.truffle.r.runtime.ffi.DLL.DotSymbol; 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 c98595d2d0a8960d78dd1488849b4c7229ccee5b..4b8b98bf799f9bbabb0383b01ad6f3be6d10ecf7 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 @@ -253,6 +253,8 @@ public final class FFIProcessor extends AbstractProcessor { w.append("import com.oracle.truffle.r.ffi.impl.common.RFFIUtils;\n"); w.append("import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;\n"); w.append("import com.oracle.truffle.r.runtime.data.RTruffleObject;\n"); + w.append("import com.oracle.truffle.r.runtime.ffi.FFIUnwrapNode;\n"); + w.append("import com.oracle.truffle.r.runtime.ffi.FFIWrapNode;\n"); w.append("\n"); w.append("// Checkstyle: stop method name check\n"); w.append("\n"); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java index cc83d8dbe5ce473224ba182e64a02bc501a4d793..5dfa769de92240a73b209a8f19fcbf87b315a4da 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java @@ -5,7 +5,7 @@ * * Copyright (c) 1995-2012, The R Core Team * Copyright (c) 2003, The R Foundation - * Copyright (c) 2015, 2017, Oracle and/or its affiliates + * Copyright (c) 2015, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -39,6 +39,7 @@ import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.ffi.CRFFI; import com.oracle.truffle.r.runtime.ffi.DLL; +import com.oracle.truffle.r.runtime.ffi.InvokeCNode; import com.oracle.truffle.r.runtime.ffi.NativeCallInfo; import com.oracle.truffle.r.runtime.ffi.RFFIFactory; import com.oracle.truffle.r.runtime.nodes.RBaseNode; @@ -55,7 +56,7 @@ public class FortranAndCFunctions { protected abstract static class CRFFIAdapter extends RBuiltinNode.Arg6 { - @Child protected CRFFI.InvokeCNode invokeCNode = RFFIFactory.getCRFFI().createInvokeCNode(); + @Child protected InvokeCNode invokeCNode = RFFIFactory.getCRFFI().createInvokeCNode(); @Override public Object[] getDefaultParameterValues() { diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/CharSXPWrapperMR.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapperMR.java similarity index 96% rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/CharSXPWrapperMR.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapperMR.java index f632643a7b287d73817527c8353d76afd289d44d..b1f47cd9b2e2e5a3c94162dd9c4ddf4a57d0887a 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/CharSXPWrapperMR.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/CharSXPWrapperMR.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.ffi.impl.interop; +package com.oracle.truffle.r.runtime.data; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; @@ -29,8 +29,6 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.data.CharSXPWrapper; -import com.oracle.truffle.r.runtime.data.RObject; import com.oracle.truffle.r.runtime.interop.RObjectNativeWrapper; @MessageResolution(receiverType = CharSXPWrapper.class) diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java index 7bddf458f755527ef10cc2b606b752dd732bdae9..eb50ba3007e580d356578053bac324f78668b6aa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java @@ -402,6 +402,7 @@ public final class NativeDataAccess { return data; } + @TruffleBoundary public static byte[] copyByteNativeData(Object mirrorObj) { NativeMirror mirror = (NativeMirror) mirrorObj; long address = mirror.dataAddress; @@ -686,16 +687,56 @@ public final class NativeDataAccess { return mirror.dataAddress; } + @TruffleBoundary + public static long allocateNativeStringArray(String[] data) { + // We allocate contiguous memory that we'll use to store both the array of pointers (char**) + // and the arrays of characters (char*). Given vector of size N, we allocate memory for N + // addresses (long) and after those we put individual strings character by character, the + // pointers from the first segment of this memory will be pointing to the starts of those + // strings. + int length = data.length; + int size = data.length * Long.BYTES; + byte[][] bytes = new byte[data.length][]; + for (int i = 0; i < length; i++) { + String element = data[i]; + bytes[i] = element.getBytes(StandardCharsets.US_ASCII); + size += bytes[i].length + 1; + } + long dataAddress = UnsafeAdapter.UNSAFE.allocateMemory(size); + long ptr = dataAddress + length * Long.BYTES; // start of the actual character data + for (int i = 0; i < length; i++) { + UnsafeAdapter.UNSAFE.putLong(dataAddress + i * 8, ptr); + UnsafeAdapter.UNSAFE.copyMemory(bytes[i], Unsafe.ARRAY_BYTE_BASE_OFFSET, null, ptr, bytes[i].length); + ptr += bytes[i].length; + UnsafeAdapter.UNSAFE.putByte(ptr++, (byte) 0); + } + assert ptr == dataAddress + size : "should have filled everything"; + return dataAddress; + } + + @TruffleBoundary + public static String[] releaseNativeStringArray(long address, int length) { + assert address != 0; + try { + String[] data = new String[length]; + for (int i = 0; i < length; i++) { + long ptr = UnsafeAdapter.UNSAFE.getLong(address + i * 8); + data[i] = readNativeString(ptr); + } + return data; + } finally { + UnsafeAdapter.UNSAFE.freeMemory(address); + } + } + @TruffleBoundary public static String readNativeString(long addr) { int len; for (len = 0; UnsafeAdapter.UNSAFE.getByte(addr + len) != 0; len++) { } byte[] bytes = new byte[len]; - for (int i = 0; i < len; i++) { - bytes[i] = UnsafeAdapter.UNSAFE.getByte(addr + i); - } - return new String(bytes); + UnsafeAdapter.UNSAFE.copyMemory(null, addr, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, len); + return new String(bytes, StandardCharsets.US_ASCII); } public static void setNativeContents(RObject obj, long address, int length) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java index b5ec016fbbbd0270999a9a3cc73f33c545d9d322..33b3cc8e805447893d58e00a99c5777910ae6936 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/StringArrayWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/StringArrayWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..a03082bf0b8f7d5bd392a2376d313ce2f3db62a0 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/StringArrayWrapper.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.ForeignAccess; +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.profiles.ConditionProfile; + +@MessageResolution(receiverType = StringArrayWrapper.class) +final class StringArrayWrapperMR { + + @Resolve(message = "IS_POINTER") + public abstract static class StringArrayWrapperIsPointerNode extends Node { + protected Object access(@SuppressWarnings("unused") StringArrayWrapper receiver) { + return true; + } + } + + @Resolve(message = "AS_POINTER") + public abstract static class StringArrayWrapperAsPointerNode extends Node { + private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); + + protected Object access(StringArrayWrapper receiver) { + long address = receiver.address; + if (profile.profile(address == 0)) { + return receiver.asPointer(); + } + return address; + } + } + + @CanResolve + public abstract static class StringArrayWrapperCheck extends Node { + protected static boolean test(TruffleObject receiver) { + return receiver instanceof StringArrayWrapper; + } + } +} + +public final class StringArrayWrapper implements TruffleObject { + + long address; + private final RStringVector vector; + + public StringArrayWrapper(RStringVector vector) { + this.vector = vector; + } + + @Override + public ForeignAccess getForeignAccess() { + return StringArrayWrapperMRForeign.ACCESS; + } + + public long asPointer() { + address = NativeDataAccess.allocateNativeStringArray(vector.getInternalManagedData()); + return address; + } + + public RStringVector copyBackFromNative() { + if (address == 0) { + return vector; + } else { + String[] contents = NativeDataAccess.releaseNativeStringArray(address, vector.getLength()); + address = 0; + RStringVector copy = new RStringVector(contents, false); + copy.copyAttributesFrom(vector); + return copy; + } + } + +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java index b2b566a04b42acfad7ea08777d82f7b3882d1c6a..1bff2fb19460c0050f65e8ba61cbf4c0b90328ae 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,402 +22,6 @@ */ package com.oracle.truffle.r.runtime.ffi; -import java.nio.charset.StandardCharsets; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.interop.CanResolve; -import com.oracle.truffle.api.interop.ForeignAccess; -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.profiles.ConditionProfile; -import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RError; -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.data.NativeDataAccess; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; -import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; -import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; -import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; -import com.oracle.truffle.r.runtime.nodes.RBaseNode; - -import sun.misc.Unsafe; - -@MessageResolution(receiverType = TemporaryWrapper.class) -class TemporaryWrapperMR { - - @Resolve(message = "IS_POINTER") - public abstract static class TemporaryWrapperIsPointerNode extends Node { - protected Object access(@SuppressWarnings("unused") TemporaryWrapper receiver) { - return true; - } - } - - @Resolve(message = "AS_POINTER") - public abstract static class TemporaryWrapperAsPointerNode extends Node { - private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); - - protected Object access(TemporaryWrapper receiver) { - long address = receiver.address; - if (profile.profile(address == 0)) { - return receiver.asPointer(); - } - return address; - } - } - - @Resolve(message = "READ") - public abstract static class TemporaryWrapperReadNode extends Node { - protected Object access(TemporaryWrapper receiver, long index) { - return receiver.read(index); - } - - protected Object access(TemporaryWrapper receiver, int index) { - return receiver.read(index); - } - } - - @Resolve(message = "WRITE") - public abstract static class TemporaryWrapperWriteNode extends Node { - // TODO: maybe this should lazily create a copy? - - protected Object access(TemporaryWrapper receiver, long index, Object value) { - receiver.write(index, value); - return value; - } - - protected Object access(TemporaryWrapper receiver, int index, Object value) { - receiver.write(index, value); - return value; - } - } - - @CanResolve - public abstract static class TemporaryWrapperCheck extends Node { - protected static boolean test(TruffleObject receiver) { - return receiver instanceof TemporaryWrapper; - } - } -} - -abstract class TemporaryWrapper implements TruffleObject { - - protected long address; - protected RAbstractAtomicVector vector; - protected boolean reuseVector = false; - - TemporaryWrapper(RAbstractAtomicVector vector) { - this.vector = vector; - } - - public Object read(long index) { - throw RInternalError.unimplemented("read at " + index); - } - - public void write(long index, Object value) { - throw RInternalError.unimplemented("write of value " + value + " at index " + index); - } - - @Override - public final ForeignAccess getForeignAccess() { - return TemporaryWrapperMRForeign.ACCESS; - } - - public long asPointer() { - // if the vector is temporary, we can re-use it. We turn it into native memory backed - // vector, keep it so and reuse it as the result. - if (vector instanceof RVector<?> && ((RVector<?>) vector).isTemporary()) { - NativeDataAccess.asPointer(vector); - reuseVector = true; - address = allocateNative(); - } else { - reuseVector = false; - address = allocate(); - } - return address; - } - - public final RAbstractAtomicVector cleanup() { - if (address == 0 || reuseVector) { - return vector; - } else { - return copyBack(); - } - } - - protected abstract long allocate(); - - protected abstract long allocateNative(); - - protected abstract RAbstractAtomicVector copyBack(); -} - -// TODO: fortran only takes a pointer to the first string -final class StringWrapper extends TemporaryWrapper { - - StringWrapper(RAbstractStringVector vector) { - super(vector); - } - - @Override - public long asPointer() { - address = allocate(); - return address; - } - - @Override - protected long allocateNative() { - throw RInternalError.shouldNotReachHere(); - } - - @Override - @TruffleBoundary - public long allocate() { - return allocateNativeStringVector((RAbstractStringVector) vector); - } - - public static long allocateNativeStringVector(RAbstractStringVector vector) { - // We allocate contiguous memory that we'll use to store both the array of pointers (char**) - // and the arrays of characters (char*). Given vector of size N, we allocate memory for N - // adresses (long) and after those we put individual strings character by character, the - // pointers from the first segment of this memory will be pointing to the starts of those - // strings. - int length = vector.getLength(); - int size = length * Long.BYTES; - byte[][] bytes = new byte[length][]; - for (int i = 0; i < length; i++) { - String element = vector.getDataAt(i); - bytes[i] = element.getBytes(StandardCharsets.US_ASCII); - size += bytes[i].length + 1; - } - long memory = UnsafeAdapter.UNSAFE.allocateMemory(size); - long ptr = memory + length * Long.BYTES; // start of the actual character data - for (int i = 0; i < length; i++) { - UnsafeAdapter.UNSAFE.putLong(memory + i * 8, ptr); - UnsafeAdapter.UNSAFE.copyMemory(bytes[i], Unsafe.ARRAY_BYTE_BASE_OFFSET, null, ptr, bytes[i].length); - ptr += bytes[i].length; - UnsafeAdapter.UNSAFE.putByte(ptr++, (byte) 0); - } - assert ptr == memory + size : "should have filled everything"; - return memory; - } - - @Override - @TruffleBoundary - protected RStringVector copyBack() { - RStringVector result = ((RAbstractStringVector) vector).materialize(); - boolean reuseResult = result.isTemporary() && !result.hasNativeMemoryData(); - String[] data = reuseResult ? result.getInternalManagedData() : new String[result.getLength()]; - for (int i = 0; i < data.length; i++) { - long ptr = UnsafeAdapter.UNSAFE.getLong(address + i * 8); - int length = 0; - while (UnsafeAdapter.UNSAFE.getByte(ptr + length) != 0) { - length++; - } - byte[] bytes = new byte[length]; - UnsafeAdapter.UNSAFE.copyMemory(null, ptr, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, length); - data[i] = new String(bytes, StandardCharsets.US_ASCII); - } - UnsafeAdapter.UNSAFE.freeMemory(address); - if (reuseResult) { - return result; - } else { - RStringVector newResult = RDataFactory.createStringVector(data, true); - newResult.copyAttributesFrom(result); - return newResult; - } - } -} - -final class IntWrapper extends TemporaryWrapper { - - IntWrapper(RAbstractIntVector vector) { - super(vector); - } - - @Override - @TruffleBoundary - public long allocate() { - RAbstractIntVector v = (RAbstractIntVector) vector; - int length = v.getLength(); - long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_INT_INDEX_SCALE); - for (int i = 0; i < length; i++) { - UnsafeAdapter.UNSAFE.putInt(memory + (i * Unsafe.ARRAY_INT_INDEX_SCALE), v.getDataAt(i)); - } - return memory; - } - - @Override - @TruffleBoundary - protected long allocateNative() { - return ((RIntVector) vector).allocateNativeContents(); - } - - @Override - @TruffleBoundary - protected RIntVector copyBack() { - RIntVector result = RDataFactory.createIntVectorFromNative(address, vector.getLength()); - result.copyAttributesFrom(vector); - return result; - } -} - -final class LogicalWrapper extends TemporaryWrapper { - - LogicalWrapper(RAbstractLogicalVector vector) { - super(vector); - } - - @Override - @TruffleBoundary - public long allocate() { - RAbstractLogicalVector v = (RAbstractLogicalVector) vector; - int length = v.getLength(); - long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_INT_INDEX_SCALE); - for (int i = 0; i < length; i++) { - UnsafeAdapter.UNSAFE.putInt(memory + (i * Unsafe.ARRAY_INT_INDEX_SCALE), RRuntime.logical2int(v.getDataAt(i))); - } - return memory; - } - - @Override - @TruffleBoundary - protected long allocateNative() { - return ((RLogicalVector) vector).allocateNativeContents(); - } - - @Override - @TruffleBoundary - protected RLogicalVector copyBack() { - RLogicalVector result = RDataFactory.createLogicalVectorFromNative(address, vector.getLength()); - result.copyAttributesFrom(vector); - return result; - } -} - -final class DoubleWrapper extends TemporaryWrapper { - - DoubleWrapper(RAbstractDoubleVector vector) { - super(vector); - } - - @Override - @TruffleBoundary - public long allocate() { - RAbstractDoubleVector v = (RAbstractDoubleVector) vector; - int length = v.getLength(); - long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE); - for (int i = 0; i < length; i++) { - UnsafeAdapter.UNSAFE.putDouble(memory + (i * Unsafe.ARRAY_DOUBLE_INDEX_SCALE), v.getDataAt(i)); - } - return memory; - } - - @Override - @TruffleBoundary - protected long allocateNative() { - return ((RDoubleVector) vector).allocateNativeContents(); - } - - @Override - @TruffleBoundary - protected RDoubleVector copyBack() { - RDoubleVector result = RDataFactory.createDoubleVectorFromNative(address, vector.getLength()); - result.copyAttributesFrom(vector); - return result; - } -} - -final class ComplexWrapper extends TemporaryWrapper { - - ComplexWrapper(RAbstractComplexVector vector) { - super(vector); - } - - @Override - @TruffleBoundary - public long allocate() { - RAbstractComplexVector v = (RAbstractComplexVector) vector; - int length = v.getLength(); - long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE * 2); - for (int i = 0; i < length; i++) { - RComplex element = v.getDataAt(i); - UnsafeAdapter.UNSAFE.putDouble(memory + (i * Unsafe.ARRAY_DOUBLE_INDEX_SCALE * 2), element.getRealPart()); - UnsafeAdapter.UNSAFE.putDouble(memory + (i * Unsafe.ARRAY_DOUBLE_INDEX_SCALE * 2) + 8, element.getImaginaryPart()); - } - return memory; - } - - @Override - @TruffleBoundary - protected long allocateNative() { - return ((RComplexVector) vector).allocateNativeContents(); - } - - @Override - @TruffleBoundary - protected RComplexVector copyBack() { - RComplexVector result = RDataFactory.createComplexVectorFromNative(address, vector.getLength()); - result.copyAttributesFrom(vector); - return result; - } -} - -final class RawWrapper extends TemporaryWrapper { - - RawWrapper(RAbstractRawVector vector) { - super(vector); - } - - @Override - @TruffleBoundary - public long allocate() { - RAbstractRawVector v = (RAbstractRawVector) vector; - VectorAccess access = v.slowPathAccess(); - try (SequentialIterator iter = access.access(v)) { - int length = access.getLength(iter); - long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_BYTE_INDEX_SCALE); - while (access.next(iter)) { - UnsafeAdapter.UNSAFE.putByte(memory + (iter.getIndex() * Unsafe.ARRAY_BYTE_INDEX_SCALE), access.getRaw(iter)); - } - return memory; - } - } - - @Override - @TruffleBoundary - protected long allocateNative() { - return ((RRawVector) vector).allocateNativeContents(); - } - - @Override - @TruffleBoundary - protected RRawVector copyBack() { - RRawVector result = RDataFactory.createRawVectorFromNative(address, vector.getLength()); - result.copyAttributesFrom(vector); - return result; - } -} - /** * Support for the {.C} and {.Fortran} calls. Arguments of these calls are only arrays of primitive * types, in the case character vectors, only the first string. The vectors coming from the R side @@ -432,83 +36,5 @@ final class RawWrapper extends TemporaryWrapper { */ public interface CRFFI { - abstract class InvokeCNode extends RBaseNode { - - /** - * Invoke the native method identified by {@code symbolInfo} passing it the arguments in - * {@code args}. The values in {@code args} should be support the IS_POINTER/AS_POINTER - * messages. - */ - protected abstract void execute(NativeCallInfo nativeCallInfo, Object[] args); - - @TruffleBoundary - protected TemporaryWrapper getNativeArgument(int index, Object vector) { - if (vector instanceof RAbstractDoubleVector) { - return new DoubleWrapper((RAbstractDoubleVector) vector); - } else if (vector instanceof RAbstractIntVector) { - return new IntWrapper((RAbstractIntVector) vector); - } else if (vector instanceof RAbstractLogicalVector) { - return new LogicalWrapper((RAbstractLogicalVector) vector); - } else if (vector instanceof RAbstractComplexVector) { - return new ComplexWrapper((RAbstractComplexVector) vector); - } else if (vector instanceof RAbstractStringVector) { - return new StringWrapper((RAbstractStringVector) vector); - } else if (vector instanceof RAbstractRawVector) { - return new RawWrapper((RAbstractRawVector) vector); - } else if (vector instanceof String) { - return new StringWrapper(RDataFactory.createStringVectorFromScalar((String) vector)); - } else if (vector instanceof Double) { - return new DoubleWrapper(RDataFactory.createDoubleVectorFromScalar((double) vector)); - } else if (vector instanceof Integer) { - return new IntWrapper(RDataFactory.createIntVectorFromScalar((int) vector)); - } else if (vector instanceof Byte) { - return new LogicalWrapper(RDataFactory.createLogicalVectorFromScalar((byte) vector)); - } else { - throw error(RError.Message.UNIMPLEMENTED_ARG_TYPE, index + 1); - } - } - - @TruffleBoundary - public final RList dispatch(NativeCallInfo nativeCallInfo, byte naok, byte dup, RArgsValuesAndNames args) { - @SuppressWarnings("unused") - boolean dupArgs = RRuntime.fromLogical(dup); - @SuppressWarnings("unused") - boolean checkNA = RRuntime.fromLogical(naok); - - // Analyze the args, making copies (ignoring dup for now) - Object[] array = new Object[args.getLength()]; - for (int i = 0; i < array.length; i++) { - array[i] = getNativeArgument(i, args.getArgument(i)); - } - - RFFIContext stateRFFI = RContext.getInstance().getStateRFFI(); - long before = stateRFFI.beforeDowncall(); - try { - execute(nativeCallInfo, array); - - // we have to assume that the native method updated everything - Object[] results = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - results[i] = ((TemporaryWrapper) array[i]).cleanup(); - } - return RDataFactory.createList(results, validateArgNames(array.length, args.getSignature())); - } finally { - stateRFFI.afterDowncall(before); - } - } - - private static RStringVector validateArgNames(int argsLength, ArgumentsSignature signature) { - String[] listArgNames = new String[argsLength]; - for (int i = 0; i < argsLength; i++) { - String name = signature.getName(i); - if (name == null) { - name = RRuntime.NAMES_ATTR_EMPTY_VALUE; - } - listArgNames[i] = name; - } - return RDataFactory.createStringVector(listArgNames, RDataFactory.COMPLETE_VECTOR); - } - } - InvokeCNode createInvokeCNode(); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIUnwrapVectorNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIUnwrapVectorNode.java new file mode 100644 index 0000000000000000000000000000000000000000..362505f05f4c0790895631257317458df88a0b76 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIUnwrapVectorNode.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.ffi; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.data.StringArrayWrapper; + +public abstract class CRFFIUnwrapVectorNode extends Node { + + public abstract Object execute(Object arg); + + @Specialization + protected Object unwrapRStringVector(StringArrayWrapper wrapper) { + return wrapper.copyBackFromNative(); + } + + @Specialization + protected Object unwrapOthers(VectorRFFIWrapper wrapper) { + return wrapper.getVector(); + } + + public abstract static class CRFFIUnwrapVectorsNode extends Node { + + public abstract Object[] execute(Object[] wrappers); + + protected CRFFIUnwrapVectorNode[] createUnwrapNodes(int length) { + CRFFIUnwrapVectorNode[] nodes = new CRFFIUnwrapVectorNode[length]; + for (int i = 0; i < nodes.length; i++) { + nodes[i] = CRFFIUnwrapVectorNodeGen.create(); + } + return nodes; + } + + @Specialization(limit = "99", guards = "wrappers.length == cachedLength") + @ExplodeLoop + protected Object[] wrapArray(Object[] wrappers, + @SuppressWarnings("unused") @Cached("wrappers.length") int cachedLength, + @Cached("createUnwrapNodes(wrappers.length)") CRFFIUnwrapVectorNode[] unwrapNodes) { + Object[] results = new Object[unwrapNodes.length]; + for (int i = 0; i < unwrapNodes.length; i++) { + results[i] = unwrapNodes[i].execute(wrappers[i]); + } + return results; + } + + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIWrapVectorNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIWrapVectorNode.java new file mode 100644 index 0000000000000000000000000000000000000000..ac1c1e530dde4d27c676b6d3a3312a27239e3c06 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIWrapVectorNode.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.ffi; + +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.interop.TruffleObject; +import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RVector; +import com.oracle.truffle.r.runtime.data.StringArrayWrapper; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public abstract class CRFFIWrapVectorNode extends Node { + + @Child FFIWrapNode wrapNode = FFIWrapNode.create(); + + public abstract Object execute(Object vector); + + public final Object dispatch(Object vector) { + return execute(wrapNode.execute(vector)); + } + + protected boolean isTemporary(Object vector) { + // if the vector is temporary, we can re-use it. We turn it into native memory backed + // vector, keep it so and reuse it as the result. + return vector instanceof RVector<?> && ((RVector<?>) vector).isTemporary(); + } + + protected static boolean isStringVector(Object vector) { + return vector instanceof RStringVector; + } + + @Specialization + protected Object temporaryToNative(RStringVector vector) { + return new StringArrayWrapper(vector); + } + + @Specialization(guards = {"isTemporary(vector)", "!isStringVector(vector)"}) + protected Object temporaryToNative(TruffleObject vector) { + return VectorRFFIWrapper.get(vector); + } + + @Specialization(guards = {"!isTemporary(vector)", "!isStringVector(vector)"}) + protected Object nonTemporaryToNative(RAbstractVector vector) { + return VectorRFFIWrapper.get(vector.copy()); + } + + @Fallback + protected VectorRFFIWrapper fallback(@SuppressWarnings("unused") Object vector) { + throw RInternalError.shouldNotReachHere("Unimplemented native conversion of argument"); + } + + public abstract static class CRFFIWrapVectorsNode extends Node { + + public abstract Object[] execute(Object[] vectors); + + protected CRFFIWrapVectorNode[] createWrapNodes(int length) { + CRFFIWrapVectorNode[] nodes = new CRFFIWrapVectorNode[length]; + for (int i = 0; i < nodes.length; i++) { + nodes[i] = CRFFIWrapVectorNodeGen.create(); + } + return nodes; + } + + @Specialization(limit = "99", guards = "vectors.length == cachedLength") + @ExplodeLoop + protected Object[] wrapArray(Object[] vectors, + @SuppressWarnings("unused") @Cached("vectors.length") int cachedLength, + @Cached("createWrapNodes(vectors.length)") CRFFIWrapVectorNode[] wrapNodes) { + Object[] results = new Object[wrapNodes.length]; + for (int i = 0; i < wrapNodes.length; i++) { + results[i] = wrapNodes[i].dispatch(vectors[i]); + } + return results; + } + + } + +} 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 dbfdc02e700e56ff4d8dee5afd273b7c07cf2447..95d5d02e8e52d7108a7ccc57ec03344c69df2c94 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 @@ -38,8 +38,9 @@ import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextKind; import com.oracle.truffle.r.runtime.context.RContext.ContextState; -import com.oracle.truffle.r.runtime.data.NativeDataAccess.CustomNativeMirror; import com.oracle.truffle.r.runtime.data.CharSXPWrapper; +import com.oracle.truffle.r.runtime.data.NativeDataAccess; +import com.oracle.truffle.r.runtime.data.NativeDataAccess.CustomNativeMirror; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RList; @@ -48,6 +49,7 @@ import com.oracle.truffle.r.runtime.data.RObject; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTruffleObject; +import com.oracle.truffle.r.runtime.data.StringArrayWrapper; import com.oracle.truffle.r.runtime.ffi.CallRFFI.InvokeVoidCallNode; import com.oracle.truffle.r.runtime.ffi.DLLRFFI.DLCloseRootNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @@ -313,7 +315,8 @@ public class DLL { @Override public long getCustomMirrorAddress() { - return StringWrapper.allocateNativeStringVector(RDataFactory.createStringVector(new String[]{path, name}, true)); + RStringVector table = RDataFactory.createStringVector(new String[]{path, name}, true); + return new StringArrayWrapper(table).asPointer(); } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIUnwrapNode.java similarity index 99% rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIUnwrapNode.java index 40a3f13e3ff2d2b2492106e3b005741412ff937c..03d1ee89b5f7ad0aba7b756bc112fe22420ff468 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIUnwrapNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIUnwrapNode.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.ffi.impl.upcalls; +package com.oracle.truffle.r.runtime.ffi; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIWrapNode.java similarity index 96% rename from com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIWrapNode.java index e6d51dbe8cf31523fe99b9882a4e1a984b8691ac..a8d8dbc2720f84685f2d1f2067eb5a11b3d6585f 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/FFIWrapNode.java @@ -20,13 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.ffi.impl.upcalls; +package com.oracle.truffle.r.runtime.ffi; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.ffi.impl.common.JavaUpCallsRFFIImpl; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -109,7 +108,7 @@ public abstract class FFIWrapNode extends Node { } @Specialization - protected static Object wrap(JavaUpCallsRFFIImpl.VectorWrapper value) { + protected static Object wrap(VectorRFFIWrapper value) { return value; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/InvokeCNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/InvokeCNode.java new file mode 100644 index 0000000000000000000000000000000000000000..ec9ab0c59a2e290383f40fad79013d17a67c5042 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/InvokeCNode.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.ffi; + +import com.oracle.truffle.api.dsl.Cached; +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.Node; +import com.oracle.truffle.r.runtime.ArgumentsSignature; +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.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.ffi.CRFFIUnwrapVectorNode.CRFFIUnwrapVectorsNode; +import com.oracle.truffle.r.runtime.ffi.CRFFIUnwrapVectorNodeGen.CRFFIUnwrapVectorsNodeGen; +import com.oracle.truffle.r.runtime.ffi.CRFFIWrapVectorNode.CRFFIWrapVectorsNode; +import com.oracle.truffle.r.runtime.ffi.CRFFIWrapVectorNodeGen.CRFFIWrapVectorsNodeGen; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; + +public abstract class InvokeCNode extends RBaseNode { + + @Child private CRFFIWrapVectorsNode argsWrapperNode = CRFFIWrapVectorsNodeGen.create(); + @Child private CRFFIUnwrapVectorsNode argsUnwrapperNode = CRFFIUnwrapVectorsNodeGen.create(); + @Child private FunctionObjectGetter functionGetterNode; + + public InvokeCNode(FunctionObjectGetter functionGetterNode) { + this.functionGetterNode = functionGetterNode; + } + + /** + * Invoke the native method identified by {@code symbolInfo} passing it the arguments in + * {@code args}. The values in {@code args} should support the IS_POINTER/AS_POINTER messages. + */ + protected abstract void execute(NativeCallInfo nativeCallInfo, Object[] args); + + public final RList dispatch(NativeCallInfo nativeCallInfo, byte naok, byte dup, RArgsValuesAndNames args) { + @SuppressWarnings("unused") + boolean dupArgs = RRuntime.fromLogical(dup); + @SuppressWarnings("unused") + boolean checkNA = RRuntime.fromLogical(naok); + + Object[] preparedArgs = argsWrapperNode.execute(args.getArguments()); + + RFFIContext stateRFFI = RContext.getInstance().getStateRFFI(); + long before = stateRFFI.beforeDowncall(); + try { + execute(nativeCallInfo, preparedArgs); + return RDataFactory.createList(argsUnwrapperNode.execute(preparedArgs), validateArgNames(preparedArgs.length, args.getSignature())); + } finally { + stateRFFI.afterDowncall(before); + } + } + + protected final TruffleObject getFunction(TruffleObject address, int arity) { + return functionGetterNode.execute(address, arity); + } + + public static Node createExecute(int n) { + return Message.createExecute(n).createNode(); + } + + @Specialization(guards = {"args.length == cachedArgsLength", "nativeCallInfo.address.asTruffleObject() == cachedAddress"}) + protected void invokeCallCached(@SuppressWarnings("unused") NativeCallInfo nativeCallInfo, Object[] args, + @SuppressWarnings("unused") @Cached("args.length") int cachedArgsLength, + @Cached("createExecute(cachedArgsLength)") Node executeNode, + @SuppressWarnings("unused") @Cached("nativeCallInfo.address.asTruffleObject()") TruffleObject cachedAddress, + @Cached("getFunction(cachedAddress, cachedArgsLength)") TruffleObject cachedFunction) { + try { + ForeignAccess.sendExecute(executeNode, cachedFunction, args); + } catch (InteropException ex) { + throw RInternalError.shouldNotReachHere(ex); + } + } + + @Specialization(replaces = "invokeCallCached", limit = "99", guards = "args.length == cachedArgsLength") + protected void invokeCallCachedLength(NativeCallInfo nativeCallInfo, Object[] args, + @Cached("args.length") int cachedArgsLength, + @Cached("createExecute(cachedArgsLength)") Node executeNode) { + try { + ForeignAccess.sendExecute(executeNode, getFunction(nativeCallInfo.address.asTruffleObject(), cachedArgsLength), args); + } catch (InteropException ex) { + throw RInternalError.shouldNotReachHere(ex); + } + } + + private static RStringVector validateArgNames(int argsLength, ArgumentsSignature signature) { + String[] listArgNames = new String[argsLength]; + for (int i = 0; i < argsLength; i++) { + String name = signature.getName(i); + if (name == null) { + name = RRuntime.NAMES_ATTR_EMPTY_VALUE; + } + listArgNames[i] = name; + } + return RDataFactory.createStringVector(listArgNames, RDataFactory.COMPLETE_VECTOR); + } + + public abstract static class FunctionObjectGetter extends Node { + + public abstract TruffleObject execute(TruffleObject address, int arity); + + } + +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/VectorRFFIWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/VectorRFFIWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..48efe8fbd709fe92a2f28e9d4b113604d44d64ae --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/VectorRFFIWrapper.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.ffi; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.Truffle; +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.interop.ArityException; +import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.ForeignAccess.StandardFactory; +import com.oracle.truffle.api.interop.Message; +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.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.CharSXPWrapper; +import com.oracle.truffle.r.runtime.data.NativeDataAccess; +import com.oracle.truffle.r.runtime.data.RComplexVector; +import com.oracle.truffle.r.runtime.data.RDoubleVector; +import com.oracle.truffle.r.runtime.data.RIntVector; +import com.oracle.truffle.r.runtime.data.RLogicalVector; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RObject; +import com.oracle.truffle.r.runtime.data.RRawVector; +import com.oracle.truffle.r.runtime.ffi.VectorRFFIWrapperFactory.VectorRFFIWrapperNativePointerFactory.DispatchAllocateNodeGen; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; + +public final class VectorRFFIWrapper implements TruffleObject { + + private final TruffleObject vector; + + public VectorRFFIWrapper(TruffleObject vector) { + assert vector instanceof RObject; + this.vector = vector; + NativeDataAccess.setNativeWrapper((RObject) vector, this); + } + + public static VectorRFFIWrapper get(TruffleObject x) { + assert x instanceof RObject; + Object wrapper = NativeDataAccess.getNativeWrapper((RObject) x); + if (wrapper != null) { + assert wrapper instanceof VectorRFFIWrapper; + return (VectorRFFIWrapper) wrapper; + } else { + wrapper = new VectorRFFIWrapper(x); + // Establish the 1-1 relationship between the object and its native wrapper + NativeDataAccess.setNativeWrapper((RObject) x, wrapper); + return (VectorRFFIWrapper) wrapper; + } + } + + public TruffleObject getVector() { + return vector; + } + + @Override + public ForeignAccess getForeignAccess() { + return VectorRFFIWrapperMRForeign.ACCESS; + } + + @Override + public int hashCode() { + return vector.hashCode(); + } + + public static class VectorRFFIWrapperNativePointer implements TruffleObject { + + private final TruffleObject vector; + + VectorRFFIWrapperNativePointer(TruffleObject vector) { + this.vector = vector; + assert vector instanceof RObject; + NativeDataAccess.asPointer(vector); // initialize the native mirror in the vector + } + + abstract static class InteropRootNode extends RootNode { + InteropRootNode() { + super(/* TruffleRLanguageImpl.getCurrentLanguage() */null); + } + + @Override + public final SourceSection getSourceSection() { + return RSyntaxNode.INTERNAL; + } + } + + // TODO: with separate version of this for the different types, it would be more efficient + // and not need the dispatch + public abstract static class DispatchAllocate extends Node { + private static final long EMPTY_DATA_ADDRESS = 0x1BAD; + + public abstract long execute(Object vector); + + @Specialization + @TruffleBoundary + protected static long get(RIntVector vector) { + return vector.allocateNativeContents(); + } + + @Specialization + @TruffleBoundary + protected static long get(RLogicalVector vector) { + return vector.allocateNativeContents(); + } + + @Specialization + @TruffleBoundary + protected static long get(RRawVector vector) { + return vector.allocateNativeContents(); + } + + @Specialization + @TruffleBoundary + protected static long get(RDoubleVector vector) { + return vector.allocateNativeContents(); + } + + @Specialization + @TruffleBoundary + protected static long get(RComplexVector vector) { + return vector.allocateNativeContents(); + } + + @Specialization + @TruffleBoundary + protected static long get(CharSXPWrapper vector) { + return vector.allocateNativeContents(); + } + + @Specialization + protected static long get(@SuppressWarnings("unused") RNull nullValue) { + // Note: GnuR is OK with, e.g., INTEGER(NULL), but it's illegal to read from or + // write to the resulting address. + return EMPTY_DATA_ADDRESS; + } + + @Fallback + protected static long get(Object vector) { + throw RInternalError.shouldNotReachHere("invalid wrapped object " + vector.getClass().getSimpleName()); + } + } + + @Override + public ForeignAccess getForeignAccess() { + return ForeignAccess.create(VectorRFFIWrapperNativePointer.class, new StandardFactory() { + @Override + public CallTarget accessIsNull() { + return Truffle.getRuntime().createCallTarget(new InteropRootNode() { + @Override + public Object execute(VirtualFrame frame) { + return false; + } + }); + } + + @Override + public CallTarget accessIsPointer() { + return Truffle.getRuntime().createCallTarget(new InteropRootNode() { + @Override + public Object execute(VirtualFrame frame) { + return true; + } + }); + } + + @Override + public CallTarget accessAsPointer() { + return Truffle.getRuntime().createCallTarget(new InteropRootNode() { + @Child private DispatchAllocate dispatch = DispatchAllocateNodeGen.create(); + + @Override + public Object execute(VirtualFrame frame) { + VectorRFFIWrapperNativePointer receiver = (VectorRFFIWrapperNativePointer) ForeignAccess.getReceiver(frame); + return dispatch.execute(receiver.vector); + } + }); + } + + @Override + public CallTarget accessToNative() { + return Truffle.getRuntime().createCallTarget(new InteropRootNode() { + @Override + public Object execute(VirtualFrame frame) { + return ForeignAccess.getReceiver(frame); + } + }); + } + }); + } + } + + @MessageResolution(receiverType = VectorRFFIWrapper.class) + public static class VectorRFFIWrapperMR { + + @Resolve(message = "IS_POINTER") + public abstract static class IntVectorWrapperNativeIsPointerNode extends Node { + protected Object access(@SuppressWarnings("unused") VectorRFFIWrapper receiver) { + return false; + } + } + + @Resolve(message = "TO_NATIVE") + public abstract static class IntVectorWrapperNativeAsPointerNode extends Node { + protected Object access(VectorRFFIWrapper receiver) { + return new VectorRFFIWrapperNativePointer(receiver.vector); + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class VectorWrapperHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") VectorRFFIWrapper receiver) { + return true; + } + } + + @Resolve(message = "GET_SIZE") + public abstract static class VectorWrapperGetSizeNode extends Node { + @Child private Node getSizeMsg = Message.GET_SIZE.createNode(); + + protected Object access(VectorRFFIWrapper receiver) { + try { + return ForeignAccess.sendGetSize(getSizeMsg, receiver.vector); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Resolve(message = "READ") + abstract static class VectorWrapperReadNode extends Node { + @Child private Node readMsg = Message.READ.createNode(); + + public Object access(VectorRFFIWrapper receiver, Object index) { + try { + return ForeignAccess.sendRead(readMsg, receiver.vector, index); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Resolve(message = "WRITE") + abstract static class VectorWrapperWriteNode extends Node { + @Child private Node writeMsg = Message.WRITE.createNode(); + + public Object access(VectorRFFIWrapper receiver, Object index, Object value) { + try { + return ForeignAccess.sendWrite(writeMsg, receiver.vector, index, value); + } catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Resolve(message = "IS_EXECUTABLE") + abstract static class VectorWrapperIsExecutableNode extends Node { + @Child private Node isExecMsg = Message.IS_EXECUTABLE.createNode(); + + public Object access(VectorRFFIWrapper receiver) { + return ForeignAccess.sendIsExecutable(isExecMsg, receiver.vector); + } + } + + @Resolve(message = "EXECUTE") + abstract static class VectorWrapperExecuteNode extends Node { + @Child private Node execMsg = Message.createExecute(0).createNode(); + + protected Object access(VectorRFFIWrapper receiver, Object[] arguments) { + try { + // Currently, there is only one "executable" object, which is + // CharSXPWrapper. + // See CharSXPWrapperMR for the EXECUTABLE message handler. + assert arguments.length == 0 && receiver.vector instanceof CharSXPWrapper; + return ForeignAccess.sendExecute(execMsg, receiver.vector); + } catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @CanResolve + public abstract static class VectorWrapperCheck extends Node { + protected static boolean test(TruffleObject receiver) { + return receiver instanceof VectorRFFIWrapper; + } + } + } + +}