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 4fd88f4a7b73ec3fcd66ba8cb69adb51108db65c..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 @@ -1360,7 +1360,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { private static VectorRFFIWrapper wrapString(String s) { CharSXPWrapper v = CharSXPWrapper.create(s); NativeDataAccess.asPointer(v); - return new VectorRFFIWrapper(v); + return VectorRFFIWrapper.get(v); } @Override 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 8c7367b7b4f4fac169b9dd94592383629c19bf18..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 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 e5babb3b23ee522afebde0e4c7c249fd76c06ad6..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 final 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); - } - } - - static 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/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.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.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 5a74d7b08bfc35032e2fdee88ce6251002b515a6..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 @@ -166,37 +166,6 @@ public final class NativeDataAccess { assert this.length == 0 || dataAddress != EMPTY_DATA_ADDRESS; } - @TruffleBoundary - void allocateNativeStringArray(String[] data) { - assert dataAddress == 0; - // 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. - 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; - } - 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"; - } - // TODO: turn this into reference queues @Override protected void finalize() throws Throwable { @@ -443,29 +412,6 @@ public final class NativeDataAccess { return data; } - @TruffleBoundary - public static String[] copyStringNativeData(Object mirrorObj) { - NativeMirror mirror = (NativeMirror) mirrorObj; - long address = mirror.dataAddress; - assert address != 0; - String[] data = new String[(int) mirror.length]; - for (int i = 0; i < data.length; i++) { - long ptr = UnsafeAdapter.UNSAFE.getLong(address + i * 8); - data[i] = readNativeString(ptr); - } - return data; - } - - @TruffleBoundary - public static String readNativeString(long addr) { - int len; - for (len = 0; UnsafeAdapter.UNSAFE.getByte(addr + len) != 0; len++) { - } - byte[] bytes = new byte[len]; - UnsafeAdapter.UNSAFE.copyMemory(null, addr, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, len); - return new String(bytes, StandardCharsets.US_ASCII); - } - // methods operating on vectors that may have a native mirror assigned: private static final Assumption noIntNative = Truffle.getRuntime().createAssumption(); @@ -474,7 +420,6 @@ public final class NativeDataAccess { private static final Assumption noComplexNative = Truffle.getRuntime().createAssumption(); private static final Assumption noRawNative = Truffle.getRuntime().createAssumption(); private static final Assumption noCharSXPNative = Truffle.getRuntime().createAssumption(); - private static final Assumption noStringArrayNative = Truffle.getRuntime().createAssumption(); static int getData(RIntVector vector, int[] data, int index) { if (noIntNative.isValid() || data != null) { @@ -672,25 +617,6 @@ public final class NativeDataAccess { } } - static String[] copyBackFromNative(RStringVector vector, String[] data) { - if (noStringArrayNative.isValid()) { - return data; - } else { - NativeMirror mirror = (NativeMirror) vector.getNativeMirror(); - assert mirror != null; - if (mirror.dataAddress == 0) { - return data; - } else { - try { - return copyStringNativeData(mirror); - } finally { - // Forget the mirror - vector.setNativeMirror(null); - } - } - } - } - static long allocateNativeContents(RLogicalVector vector, byte[] data, int length) { NativeMirror mirror = (NativeMirror) vector.getNativeMirror(); assert mirror != null; @@ -761,15 +687,56 @@ public final class NativeDataAccess { return mirror.dataAddress; } - static long allocateNativeContents(RStringVector vector, String[] data) { - NativeMirror mirror = (NativeMirror) vector.getNativeMirror(); - assert mirror != null; - assert mirror.dataAddress == 0 ^ data == null; - if (mirror.dataAddress == 0) { - noStringArrayNative.invalidate(); - mirror.allocateNativeStringArray(data); + @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); } - return mirror.dataAddress; + } + + @TruffleBoundary + public static String readNativeString(long addr) { + int len; + for (len = 0; UnsafeAdapter.UNSAFE.getByte(addr + len) != 0; len++) { + } + byte[] bytes = new byte[len]; + 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 9b8bf51ee84e483363792e93862c6bc3737b54a5..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 @@ -40,11 +40,10 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck; public final class RStringVector extends RVector<String[]> implements RAbstractStringVector { - private String[] data; + private final String[] data; RStringVector(String[] data, boolean complete) { super(complete); - assert data != null; this.data = data; assert RAbstractVector.verify(this); } @@ -99,18 +98,6 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS return data.length; } - public long allocateNativeContents() { - return NativeDataAccess.allocateNativeContents(this, data); - } - - public RStringVector copyBackFromNative() { - String[] contents = NativeDataAccess.copyBackFromNative(this, data); - if (contents != data) { - data = contents; - } - return this; - } - @Override public String[] getDataCopy() { String[] copy = new String[data.length]; 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 52770c4a7e9a94558b08e79aa84a092f9f519d6d..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 @@ -22,19 +22,6 @@ */ package com.oracle.truffle.r.runtime.ffi; -import com.oracle.truffle.r.runtime.ArgumentsSignature; -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.UnwrapVectorNode.UnwrapVectorsNode; -import com.oracle.truffle.r.runtime.ffi.UnwrapVectorNodeGen.UnwrapVectorsNodeGen; -import com.oracle.truffle.r.runtime.ffi.WrapVectorNode.WrapVectorsNode; -import com.oracle.truffle.r.runtime.ffi.WrapVectorNodeGen.WrapVectorsNodeGen; -import com.oracle.truffle.r.runtime.nodes.RBaseNode; - /** * 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 @@ -49,48 +36,5 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode; */ public interface CRFFI { - abstract class InvokeCNode extends RBaseNode { - - @Child WrapVectorsNode argsWrapperNode = WrapVectorsNodeGen.create(); - @Child UnwrapVectorsNode argsUnwrapperNode = UnwrapVectorsNodeGen.create(); - - /** - * 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); - - 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); - - VectorRFFIWrapper[] 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); - } - } - - 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/UnwrapVectorNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIUnwrapVectorNode.java similarity index 61% rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UnwrapVectorNode.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIUnwrapVectorNode.java index 5f04b7287c5e6278e7dde9096d446add6123866b..362505f05f4c0790895631257317458df88a0b76 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/UnwrapVectorNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIUnwrapVectorNode.java @@ -23,51 +23,42 @@ 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.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.StringArrayWrapper; -public abstract class UnwrapVectorNode extends Node { +public abstract class CRFFIUnwrapVectorNode extends Node { - public abstract Object execute(VectorRFFIWrapper arg); + public abstract Object execute(Object arg); - protected static boolean isRStringVector(VectorRFFIWrapper wrapper) { - return wrapper.getVector() instanceof RStringVector; + @Specialization + protected Object unwrapRStringVector(StringArrayWrapper wrapper) { + return wrapper.copyBackFromNative(); } - @Specialization(guards = "isRStringVector(wrapper)") - protected Object unwrapRStringVector(VectorRFFIWrapper wrapper) { - return ((RStringVector) wrapper.getVector()).copyBackFromNative(); - } - - @Specialization(guards = "!isRStringVector(wrapper)") + @Specialization protected Object unwrapOthers(VectorRFFIWrapper wrapper) { return wrapper.getVector(); } - public abstract static class UnwrapVectorsNode extends Node { + public abstract static class CRFFIUnwrapVectorsNode extends Node { - public abstract Object[] execute(VectorRFFIWrapper[] wrappers); + public abstract Object[] execute(Object[] wrappers); - protected UnwrapVectorNode[] createUnwrapNodes(int length) { - UnwrapVectorNode[] nodes = new UnwrapVectorNode[length]; + protected CRFFIUnwrapVectorNode[] createUnwrapNodes(int length) { + CRFFIUnwrapVectorNode[] nodes = new CRFFIUnwrapVectorNode[length]; for (int i = 0; i < nodes.length; i++) { - nodes[i] = UnwrapVectorNodeGen.create(); + nodes[i] = CRFFIUnwrapVectorNodeGen.create(); } return nodes; } @Specialization(limit = "99", guards = "wrappers.length == cachedLength") @ExplodeLoop - protected Object[] wrapArray(VectorRFFIWrapper[] wrappers, + protected Object[] wrapArray(Object[] wrappers, @SuppressWarnings("unused") @Cached("wrappers.length") int cachedLength, - @Cached("createUnwrapNodes(wrappers.length)") UnwrapVectorNode[] unwrapNodes) { + @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]); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/WrapVectorNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIWrapVectorNode.java similarity index 66% rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/WrapVectorNode.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIWrapVectorNode.java index 54a0320195330f8c748ffab4fe093ffeb32b7352..ac1c1e530dde4d27c676b6d3a3312a27239e3c06 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/WrapVectorNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFIWrapVectorNode.java @@ -29,32 +29,43 @@ 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 WrapVectorNode extends Node { +public abstract class CRFFIWrapVectorNode extends Node { @Child FFIWrapNode wrapNode = FFIWrapNode.create(); - public abstract VectorRFFIWrapper execute(Object vector); + public abstract Object execute(Object vector); - public final VectorRFFIWrapper dispatch(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()); + return vector instanceof RVector<?> && ((RVector<?>) vector).isTemporary(); } - @Specialization(guards = "isTemporary(vector)") - protected VectorRFFIWrapper temporaryToNative(TruffleObject vector) { + 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)") - protected VectorRFFIWrapper nonTemporaryToNative(RAbstractVector vector) { + @Specialization(guards = {"!isTemporary(vector)", "!isStringVector(vector)"}) + protected Object nonTemporaryToNative(RAbstractVector vector) { return VectorRFFIWrapper.get(vector.copy()); } @@ -63,24 +74,24 @@ public abstract class WrapVectorNode extends Node { throw RInternalError.shouldNotReachHere("Unimplemented native conversion of argument"); } - public abstract static class WrapVectorsNode extends Node { + public abstract static class CRFFIWrapVectorsNode extends Node { - public abstract VectorRFFIWrapper[] execute(Object[] vectors); + public abstract Object[] execute(Object[] vectors); - protected WrapVectorNode[] createWrapNodes(int length) { - WrapVectorNode[] nodes = new WrapVectorNode[length]; + protected CRFFIWrapVectorNode[] createWrapNodes(int length) { + CRFFIWrapVectorNode[] nodes = new CRFFIWrapVectorNode[length]; for (int i = 0; i < nodes.length; i++) { - nodes[i] = WrapVectorNodeGen.create(); + nodes[i] = CRFFIWrapVectorNodeGen.create(); } return nodes; } @Specialization(limit = "99", guards = "vectors.length == cachedLength") @ExplodeLoop - protected VectorRFFIWrapper[] wrapArray(Object[] vectors, + protected Object[] wrapArray(Object[] vectors, @SuppressWarnings("unused") @Cached("vectors.length") int cachedLength, - @Cached("createWrapNodes(vectors.length)") WrapVectorNode[] wrapNodes) { - VectorRFFIWrapper[] results = new VectorRFFIWrapper[wrapNodes.length]; + @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]); } 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 6a9731b2cb88cb82b0dab1d1a01916c8167fabd2..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 @@ -49,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; @@ -315,8 +316,7 @@ public class DLL { @Override public long getCustomMirrorAddress() { RStringVector table = RDataFactory.createStringVector(new String[]{path, name}, true); - NativeDataAccess.asPointer(table); - return table.allocateNativeContents(); + return new StringArrayWrapper(table).asPointer(); } } 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 index 518474a9e68197834b0921f8a260071f04ac0cca..48efe8fbd709fe92a2f28e9d4b113604d44d64ae 100644 --- 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 @@ -52,7 +52,6 @@ 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.data.RStringVector; import com.oracle.truffle.r.runtime.ffi.VectorRFFIWrapperFactory.VectorRFFIWrapperNativePointerFactory.DispatchAllocateNodeGen; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @@ -152,12 +151,6 @@ public final class VectorRFFIWrapper implements TruffleObject { return vector.allocateNativeContents(); } - @Specialization - @TruffleBoundary - protected static long get(RStringVector vector) { - return vector.allocateNativeContents(); - } - @Specialization @TruffleBoundary protected static long get(CharSXPWrapper vector) {