From d11c1319dd65c82d5fd5fa200dd3247509ac5e49 Mon Sep 17 00:00:00 2001 From: Florian Angerer <florian.angerer@oracle.com> Date: Mon, 22 Jan 2018 18:54:20 +0100 Subject: [PATCH] Added minimal implementation for 'eSoftVersion' and 'La_library'. --- .../impl/interop/base/ESoftVersionResult.java | 46 +++++++++++++++ .../interop/base/ESoftVersionResultMR.java | 58 +++++++++++++++++++ .../r/ffi/impl/llvm/TruffleLLVM_Base.java | 23 ++++++++ .../r/ffi/impl/managed/Managed_Base.java | 5 ++ .../r/ffi/impl/nfi/TruffleNFI_Base.java | 24 ++++++++ .../fficall/src/truffle_common/base_rffi.c | 15 +++++ .../r/nodes/builtin/base/BasePackage.java | 1 + .../nodes/builtin/base/DynLoadFunctions.java | 50 ++++++++++------ .../r/nodes/builtin/base/LaFunctions.java | 15 ++++- .../truffle/r/runtime/RCompression.java | 32 ++++++++++ .../truffle/r/runtime/ffi/BaseRFFI.java | 11 ++++ .../truffle/r/runtime/ffi/NativeFunction.java | 1 + 12 files changed, 263 insertions(+), 18 deletions(-) create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java new file mode 100644 index 0000000000..a3e8e86c2f --- /dev/null +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java @@ -0,0 +1,46 @@ +/* + * 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.ffi.impl.interop.base; + +import java.util.HashMap; +import java.util.Map; + +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.r.runtime.data.RTruffleObject; + +public final class ESoftVersionResult implements RTruffleObject { + private final Map<String, String> paths = new HashMap<>(); + + public void putVersion(String libName, String version) { + paths.put(libName, version); + } + + public Map<String, String> getVersions() { + return paths; + } + + @Override + public ForeignAccess getForeignAccess() { + return ESoftVersionResultMRForeign.ACCESS; + } +} diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java new file mode 100644 index 0000000000..fc958b7b30 --- /dev/null +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java @@ -0,0 +1,58 @@ +/* + * 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.ffi.impl.interop.base; + +import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; + +@MessageResolution(receiverType = ESoftVersionResult.class) +public class ESoftVersionResultMR { + @CanResolve + public abstract static class ESoftVersionResultCallbackCheck extends Node { + + protected static boolean test(TruffleObject receiver) { + return receiver instanceof ESoftVersionResult; + } + } + + @Resolve(message = "IS_EXECUTABLE") + public abstract static class ESoftVersionResultIsExecutable extends Node { + protected Object access(@SuppressWarnings("unused") ESoftVersionResult receiver) { + return true; + } + } + + @Resolve(message = "EXECUTE") + public abstract static class ESoftVersionResultCallbackExecute extends Node { + protected Object access(ESoftVersionResult receiver, Object[] arguments) { + if (arguments.length == 2) { + receiver.putVersion("zlib", arguments[0].toString()); + receiver.putVersion("PCRE", arguments[1].toString()); + } + return receiver; + } + } +} diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java index bfe843a1f8..a7b39d2b3f 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java @@ -24,8 +24,10 @@ package com.oracle.truffle.r.ffi.impl.llvm; import java.io.IOException; import java.util.ArrayList; +import java.util.Map; import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray; +import com.oracle.truffle.r.ffi.impl.interop.base.ESoftVersionResult; import com.oracle.truffle.r.ffi.impl.interop.base.GlobResult; import com.oracle.truffle.r.ffi.impl.interop.base.ReadlinkResult; import com.oracle.truffle.r.ffi.impl.interop.base.StrtolResult; @@ -224,6 +226,22 @@ public class TruffleLLVM_Base implements BaseRFFI { } } + private static class TruffleLLVM_ESoftVersionNode extends TruffleLLVM_DownCallNode implements ESoftVersionNode { + + @Override + protected NativeFunction getFunction() { + return NativeFunction.eSoftVersion; + } + + @Override + public Map<String, String> eSoftVersion() { + ESoftVersionResult result = new ESoftVersionResult(); + call(result); + return result.getVersions(); + } + + } + @Override public GetpidNode createGetpidNode() { return new TruffleLLVM_GetpidNode(); @@ -273,4 +291,9 @@ public class TruffleLLVM_Base implements BaseRFFI { public GlobNode createGlobNode() { return new TruffleLLVM_GlobNode(); } + + @Override + public ESoftVersionNode createESoftVersionNode() { + return new TruffleLLVM_ESoftVersionNode(); + } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java index 185cf45f55..b13db5a861 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java @@ -200,4 +200,9 @@ public class Managed_Base implements BaseRFFI { public GlobNode createGlobNode() { return null; } + + @Override + public ESoftVersionNode createESoftVersionNode() { + return null; + } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java index 7628b86c76..3025b6f127 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java @@ -24,9 +24,11 @@ package com.oracle.truffle.r.ffi.impl.nfi; import java.io.IOException; import java.util.ArrayList; +import java.util.Map; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.java.JavaInterop; +import com.oracle.truffle.r.ffi.impl.interop.base.ESoftVersionResult; import com.oracle.truffle.r.ffi.impl.interop.base.GlobResult; import com.oracle.truffle.r.ffi.impl.interop.base.ReadlinkResult; import com.oracle.truffle.r.ffi.impl.interop.base.StrtolResult; @@ -214,6 +216,22 @@ public class TruffleNFI_Base implements BaseRFFI { } } + private static class TruffleNFI_ESoftVersionNode extends TruffleNFI_DownCallNode implements ESoftVersionNode { + + @Override + protected NativeFunction getFunction() { + return NativeFunction.eSoftVersion; + } + + @Override + public Map<String, String> eSoftVersion() { + ESoftVersionResult result = new ESoftVersionResult(); + call(result); + return result.getVersions(); + } + + } + @Override public GetpidNode createGetpidNode() { return new TruffleNFI_GetpidNode(); @@ -263,4 +281,10 @@ public class TruffleNFI_Base implements BaseRFFI { public GlobNode createGlobNode() { return new TruffleNFI_GlobNode(); } + + @Override + public ESoftVersionNode createESoftVersionNode() { + return new TruffleNFI_ESoftVersionNode(); + } + } diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c index 25215c77f1..517836d645 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c +++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c @@ -107,3 +107,18 @@ void call_base_strtol(void (*call_setresult)(long result, int cerrno), char *s, long rc = strtol(s, NULL, base); call_setresult(rc, errno); } + +#include <zlib.h> +#include <bzlib.h> +#ifdef HAVE_PCRE_PCRE_H +# include <pcre/pcre.h> +#else +# include <pcre.h> +#endif +void call_base_eSoftVersion(void (*call_eSoftVersion_setfields)(char *zlibVersion, char *pcreVersion)) { + + char sZlibVersion[256], sPcreVersion[256]; + snprintf(sZlibVersion, 256, "%s", zlibVersion()); + snprintf(sPcreVersion, 256, "%s", pcre_version()); + call_eSoftVersion_setfields(sZlibVersion, sPcreVersion); +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 0544dabb50..a3930beaac 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -600,6 +600,7 @@ public class BasePackage extends RBuiltinPackage { add(LaFunctions.Version.class, LaFunctionsFactory.VersionNodeGen::create); add(LaFunctions.LaSolve.class, LaFunctionsFactory.LaSolveNodeGen::create); add(LaFunctions.Svd.class, LaFunctionsFactory.SvdNodeGen::create); + add(LaFunctions.LaLibrary.class, LaFunctionsFactory.LaLibraryNodeGen::create); add(Lapply.class, LapplyNodeGen::create); add(Length.class, LengthNodeGen::create); add(Lengths.class, LengthsNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java index 8eebeae3cd..12eb630eff 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java @@ -33,15 +33,18 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; +import java.util.List; import java.util.Map; 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.r.ffi.impl.common.LibPaths; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.RCompression; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; @@ -51,6 +54,8 @@ import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.ffi.BaseRFFI; +import com.oracle.truffle.r.runtime.ffi.BaseRFFI.ESoftVersionNode; import com.oracle.truffle.r.runtime.ffi.DLL; import com.oracle.truffle.r.runtime.ffi.DLL.DLLException; import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo; @@ -223,6 +228,7 @@ public class DynLoadFunctions { @RBuiltin(name = "eSoftVersion", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE) public abstract static class ExtSoftVersion extends RBuiltinNode.Arg0 { + @Child private ESoftVersionNode eSoftVersionNode = BaseRFFI.ESoftVersionNode.create(); static { Casts.noCasts(ExtSoftVersion.class); @@ -231,22 +237,32 @@ public class DynLoadFunctions { @Specialization @TruffleBoundary protected RStringVector getSymbolInfo() { - String[] data = new String[]{"zlib", "bzlib", "xz", "PCRE", "ICU", "TRE", "iconv"}; - RStringVector names = RDataFactory.createStringVector(data, true); - - Map<String, String> versionFunctionTable = new HashMap<>(); - versionFunctionTable.put("zlib", "zlibVersion"); - versionFunctionTable.put("bzlib", "BZ2_bzlibVersion"); - versionFunctionTable.put("xz", "lzma_version_string"); - versionFunctionTable.put("PCRE", "pcre_version"); - versionFunctionTable.put("TRE", "tre_version"); - - // TODO - - // ICU -> empty - // TRE mandatory - // iconv -> unknown - return RDataFactory.createStringVector(0); + + Map<String, String> eSoftVersion = eSoftVersionNode.eSoftVersion(); + + List<String> libNames = new ArrayList<>(); + List<String> versions = new ArrayList<>(); + + for (Map.Entry<String, String> versionEntry : eSoftVersion.entrySet()) { + libNames.add(versionEntry.getKey()); + versions.add(versionEntry.getValue()); + } + + // BZIP2 + try { + versions.add(RCompression.getBz2Version()); + libNames.add("bzip2"); + } catch (IOException e) { + // ignore + } + + // BLAS + libNames.add("BLAS"); + versions.add(LibPaths.getBuiltinLibPath("Rblas")); + + RStringVector names = RDataFactory.createStringVector(libNames.toArray(new String[0]), true); + return RDataFactory.createStringVector(versions.toArray(new String[0]), true, names); + } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java index a75d886e0a..49f5c90d3a 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java @@ -41,6 +41,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.ffi.impl.common.LibPaths; import com.oracle.truffle.r.nodes.access.vector.ExtractListElement; import com.oracle.truffle.r.nodes.attributes.CopyAttributesNode; import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode; @@ -63,7 +64,6 @@ import com.oracle.truffle.r.runtime.data.RComplexVector; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -866,4 +866,17 @@ public class LaFunctions { return RDataFactory.createList(val, nm); } } + + @RBuiltin(name = "La_library", kind = INTERNAL, parameterNames = {}, behavior = PURE) + public abstract static class LaLibrary extends RBuiltinNode.Arg0 { + + static { + Casts.noCasts(LaLibrary.class); + } + + @Specialization + protected Object doLibrary() { + return RDataFactory.createStringVector(LibPaths.getBuiltinLibPath("Rlapack")); + } + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java index d95a86df37..1f3cf0a6fb 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java @@ -250,4 +250,36 @@ public class RCompression { } throw new IOException(); } + + public static String getBz2Version() throws IOException { + // assumes: "bzip2, a block-sorting file compressor. Version 1.0.6, 6-Sept-2010." + String[] command = {"bzip2", "-V"}; + int rc; + ProcessBuilder pb = new ProcessBuilder(command); + Process p = pb.start(); + // version is written to the error output stream + InputStream is = p.getErrorStream(); + ProcessOutputManager.OutputThreadVariable readThread = new ProcessOutputManager.OutputThreadVariable(command[0], is); + readThread.start(); + try { + rc = p.waitFor(); + if (rc == 0) { + String output = new String(readThread.getData()); + String version = "Version "; + String firstLine = output.split("\\n")[0]; + int versionIdx = firstLine.indexOf(version); + if (versionIdx >= 0) { + int commaIdx = firstLine.lastIndexOf('.'); + if (commaIdx > versionIdx) { + return firstLine.substring(versionIdx + version.length(), commaIdx); + } + } + } else { + throw new IOException("bzip2 error code: " + rc); + } + } catch (InterruptedException ex) { + // fall through + } + throw new IOException(); + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java index ed2fdc7b53..4bbcbb461e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java @@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.ffi; import java.io.IOException; import java.util.ArrayList; +import java.util.Map; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInterface; @@ -163,6 +164,14 @@ public interface BaseRFFI { } } + interface ESoftVersionNode extends NodeInterface { + Map<String, String> eSoftVersion(); + + static ESoftVersionNode create() { + return RFFIFactory.getBaseRFFI().createESoftVersionNode(); + } + } + /* * The RFFI implementation influences exactly what subclass of the above nodes is created. Each * implementation must therefore, implement these methods that are called by the associated @@ -189,6 +198,8 @@ public interface BaseRFFI { GlobNode createGlobNode(); + ESoftVersionNode createESoftVersionNode(); + /* * Some functions are called from non-Truffle contexts, which requires a RootNode */ diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java index 77e64b651b..7ea60974f1 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java @@ -43,6 +43,7 @@ public enum NativeFunction { strtol("((sint64, sint32): void, string, sint32): void", "call_base_"), uname("((string, string, string, string, string): void): void", "call_base_"), glob("((string): void, string): void", "call_base_"), + eSoftVersion("((string, string): void): void", "call_base_"), // PCRE maketables("(): sint64", "call_pcre_"), compile("((uint64, string, sint32): void, string, sint32, uint64): void", "call_pcre_"), -- GitLab