From d6d2bda05b31736ec74f090aa3c3adbd329ad70f Mon Sep 17 00:00:00 2001 From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com> Date: Fri, 2 Mar 2018 18:18:09 +0100 Subject: [PATCH] Dynamic linking of native libs with LLVM libs --- .../ffi/impl/common/JavaUpCallsRFFIImpl.java | 166 +++++++++--------- .../r/ffi/impl/interop/package-info.java | 6 +- .../r/ffi/impl/llvm/TruffleLLVM_Context.java | 4 - .../r/ffi/impl/llvm/TruffleLLVM_DLL.java | 92 ++++++++-- .../r/ffi/impl/llvm/tools/ShowLLVMIR.java | 6 +- .../upcalls/BytesToNativeCharArrayCallMR.java | 2 +- .../ffi/impl/nodes/NativeStringCastNode.java | 22 +++ com.oracle.truffle.r.native/Makefile | 17 +- com.oracle.truffle.r.native/fficall/Makefile | 7 +- .../fficall/src/truffle_llvm/Memory.c | 3 +- .../gnur/patch/src/library/Makefile | 5 +- .../gnur/patch/src/library/stats/Makefile | 3 +- .../llvm_tools/llvm-c++ | 2 +- .../llvm_tools/llvm-cc | 2 +- .../llvm_tools/llvm-helper | 46 +++-- .../r/runtime/data/NativeDataAccess.java | 48 ++++- .../truffle/r/runtime/data/RObject.java | 16 -- .../truffle/r/runtime/data/RPairList.java | 4 +- 18 files changed, 280 insertions(+), 171 deletions(-) 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 3f524ddfaa..523b80e3b1 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 @@ -906,9 +906,9 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { } /** - * Helper function for {@code R_TopLevelExec} which is similar to {@code R_TryEval} except that a C - * function is invoked (in the native layer) instead of an R expression. assert: this is ONLY called - * from R_TopLevelExec prior to calling C function. + * Helper function for {@code R_TopLevelExec} which is similar to {@code R_TryEval} except that + * a C function is invoked (in the native layer) instead of an R expression. assert: this is + * ONLY called from R_TopLevelExec prior to calling C function. */ @Override @TruffleBoundary @@ -1826,101 +1826,101 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { } }); } + } - @MessageResolution(receiverType = VectorWrapper.class) - public static class VectorWrapperMR { + @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 = "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 = "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 = "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(); + @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); - } + 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(); + @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); - } + 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(); + @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); - } + 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(); + @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); - } + 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); - } + @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; - } + @CanResolve + public abstract static class VectorWrapperCheck extends Node { + protected static boolean test(TruffleObject receiver) { + return receiver instanceof VectorWrapper; } } } @@ -1930,19 +1930,20 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { private final TruffleObject vector; public VectorWrapper(TruffleObject vector) { + assert vector instanceof RObject; this.vector = vector; - ((RObject) vector).setNativeWrapper(this); + NativeDataAccess.setNativeWrapper((RObject) vector, this); } static Object get(TruffleObject x) { assert x instanceof RObject; - Object wrapper = ((RObject) x).getNativeWrapper(); + 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 - ((RObject) x).setNativeWrapper(wrapper); + NativeDataAccess.setNativeWrapper((RObject) x, wrapper); return wrapper; } } @@ -1966,12 +1967,8 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override public Object INTEGER(Object x) { // also handles LOGICAL - assert x instanceof RIntVector || x instanceof RLogicalVector || x == RNull.instance || x instanceof RUnboundValue : "" + x + ":" + x.getClass(); - if (x instanceof RUnboundValue) { - return VectorWrapper.get((RUnboundValue) x); - } else { - return VectorWrapper.get(guaranteeVectorOrNull(x, RVector.class)); - } + assert x instanceof RIntVector || x instanceof RLogicalVector || x == RNull.instance; + return VectorWrapper.get(guaranteeVectorOrNull(x, RVector.class)); } @Override @@ -1996,12 +1993,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override public Object R_CHAR(Object x) { - TruffleObject xto = guaranteeVectorOrNull(x, CharSXPWrapper.class); - if (xto == RNull.instance) { - return xto; - } - CharSXPWrapper chw = (CharSXPWrapper) xto; - return VectorWrapper.get(chw); + return VectorWrapper.get(guaranteeVectorOrNull(x, CharSXPWrapper.class)); } @Override diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java index 41e4198d9e..fc661a180f 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,9 +23,5 @@ /** * A collection of types and {@link com.oracle.truffle.api.interop.MessageResolution} classes that * support the implementations. - * - * See com.oracle.truffle.r.ffi.impl.interop.base and com.oracle.truffle.r.ffi.impl.interop.pcre for - * similar classes specific to the {@link com.oracle.truffle.r.runtime.ffi.BaseRFFI} and - * {@link com.oracle.truffle.r.runtime.ffi.PCRERFFI} interfaces. */ package com.oracle.truffle.r.ffi.impl.interop; diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Context.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Context.java index 87b27410ab..65330af2da 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Context.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Context.java @@ -86,10 +86,6 @@ final class TruffleLLVM_Context extends RFFIContext { String libzPath = LibPaths.getBuiltinLibPath("z"); TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(libzPath, false, true); - - // String curlPath = LibPaths.getBuiltinLibPath("curl.4"); - String curlPath = "libcurl.so"; - TruffleLLVM_NativeDLL.NativeDLOpenRootNode.create().getCallTarget().call(curlPath, false, true); } @Override diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java index a1ba42a713..f934408376 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java @@ -23,14 +23,22 @@ package com.oracle.truffle.r.ffi.impl.llvm; import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintStream; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -39,6 +47,8 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RPlatform; +import com.oracle.truffle.r.runtime.RPlatform.OSInfo; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextState; import com.oracle.truffle.r.runtime.ffi.DLL; @@ -63,12 +73,24 @@ import com.oracle.truffle.r.runtime.ffi.DLLRFFI; * */ public class TruffleLLVM_DLL implements DLLRFFI { + /* + * The LIBS file, which is included in the LLVM archive, enumerates native dynamic libraries to + * be linked with the LLVM library in the archive. + */ + private static final String LIBS = "LIBS"; + + private static final Set<String> ignoredNativeLibs = new HashSet<>(); + static { + ignoredNativeLibs.add("Rblas"); + ignoredNativeLibs.add("Rlapack"); + } + static class ContextStateImpl implements RContext.ContextState { /** - * When a new {@link RContext} is created we have to re-parse the libR modules, unfortunately, as - * there is no way to propagate the LLVM state created in the initial context. TODO when do we - * really need to do this? This is certainly too early for contexts that will not invoke LLVM code - * (e.g. most unit tests) + * When a new {@link RContext} is created we have to re-parse the libR modules, + * unfortunately, as there is no way to propagate the LLVM state created in the initial + * context. TODO when do we really need to do this? This is certainly too early for contexts + * that will not invoke LLVM code (e.g. most unit tests) */ @Override public ContextState initialize(RContext context) { @@ -121,7 +143,19 @@ public class TruffleLLVM_DLL implements DLLRFFI { boolean match(String name); } - public static LLVM_IR[] getZipLLVMIR(String path) { + public static final class LLVMArchive { + public final LLVM_IR[] irs; + public final List<String> nativeLibs; + + private LLVMArchive(LLVM_IR[] irs, List<String> nativeLibs) { + super(); + this.irs = irs; + this.nativeLibs = nativeLibs; + } + } + + public static LLVMArchive getZipLLVMIR(String path) { + List<String> nativeLibs = Collections.emptyList(); try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(path)))) { ArrayList<LLVM_IR> irList = new ArrayList<>(); while (true) { @@ -130,24 +164,28 @@ public class TruffleLLVM_DLL implements DLLRFFI { break; } int size = (int) entry.getSize(); - byte[] bc = new byte[size]; + byte[] bytes = new byte[size]; int n; int totalRead = 0; - while (totalRead < size && (n = zis.read(bc, totalRead, size - totalRead)) != -1) { + while (totalRead < size && (n = zis.read(bytes, totalRead, size - totalRead)) != -1) { totalRead += n; } + if (LIBS.equals(entry.getName())) { + nativeLibs = getNativeLibs(bytes); + continue; + } Path zipName = Paths.get(entry.getName()); String name = zipName.getFileName().toString(); int ix = name.indexOf('.'); if (ix > 0) { name = name.substring(0, ix); } - LLVM_IR.Binary ir = new LLVM_IR.Binary(name, bc); + LLVM_IR.Binary ir = new LLVM_IR.Binary(name, bytes); irList.add(ir); // debugging if (System.getenv("FASTR_LLVM_DEBUG") != null) { try (FileOutputStream bs = new FileOutputStream(Paths.get("tmpzip", name).toString())) { - bs.write(bc); + bs.write(bytes); } try (PrintStream bs = new PrintStream(new FileOutputStream(Paths.get("tmpb64", name).toString()))) { bs.print(ir.base64); @@ -156,25 +194,38 @@ public class TruffleLLVM_DLL implements DLLRFFI { } LLVM_IR[] result = new LLVM_IR[irList.size()]; irList.toArray(result); - return result; + return new LLVMArchive(result, nativeLibs); } catch (IOException ex) { // not a zip file return null; } } + private static List<String> getNativeLibs(byte[] bytes) throws IOException { + List<String> libs = new LinkedList<>(); + try (BufferedReader libReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)))) { + String lib = null; + while ((lib = libReader.readLine()) != null) { + libs.add(lib); + } + } + return libs; + } + private static class TruffleLLVM_DLOpenNode extends Node implements DLOpenNode { @Child private TruffleLLVM_NativeDLL.TruffleLLVM_NativeDLOpen nativeDLLOpenNode; /** - * If a library is enabled for LLVM, the IR for all the modules is retrieved and analyzed. Every - * exported symbol in the module added to the parseStatus map for the current {@link RContext}. This - * allows {@code dlsym} to definitively locate any symbol, even if the IR has not been parsed yet. + * If a library is enabled for LLVM, the IR for all the modules is retrieved and analyzed. + * Every exported symbol in the module added to the parseStatus map for the current + * {@link RContext}. This allows {@code dlsym} to definitively locate any symbol, even if + * the IR has not been parsed yet. */ @Override public Object execute(String path, boolean local, boolean now) { try { - LLVM_IR[] irs = getZipLLVMIR(path); + LLVMArchive ar = getZipLLVMIR(path); + LLVM_IR[] irs = ar.irs; if (irs == null) { return tryOpenNative(path, local, now); } @@ -182,6 +233,8 @@ public class TruffleLLVM_DLL implements DLLRFFI { if (libName.equals("libR")) { // save for new RContexts truffleDLL.libRModules = irs; + } else { + loadNativeLibs(ar.nativeLibs); } for (LLVM_IR ir : irs) { parseLLVM(libName, ir); @@ -203,6 +256,17 @@ public class TruffleLLVM_DLL implements DLLRFFI { } } + private void loadNativeLibs(List<String> nativeLibs) { + OSInfo osInfo = RPlatform.getOSInfo(); + for (String nativeLib : nativeLibs) { + if (ignoredNativeLibs.contains(nativeLib)) { + continue; + } + String nativeLibName = "lib" + nativeLib + "." + osInfo.libExt; + tryOpenNative(nativeLibName, false, true); + } + } + private long tryOpenNative(String path, boolean local, boolean now) throws UnsatisfiedLinkError { if (nativeDLLOpenNode == null) { nativeDLLOpenNode = insert(new TruffleLLVM_NativeDLL.TruffleLLVM_NativeDLOpen()); diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.java index 91acc85892..a606291213 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/tools/ShowLLVMIR.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 @@ -28,6 +28,7 @@ import java.io.OutputStream; import com.oracle.truffle.r.ffi.impl.llvm.LLVM_IR; import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_DLL; +import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_DLL.LLVMArchive; import com.oracle.truffle.r.runtime.ProcessOutputManager; public class ShowLLVMIR { @@ -64,7 +65,8 @@ public class ShowLLVMIR { usage(); } try { - LLVM_IR[] irs = TruffleLLVM_DLL.getZipLLVMIR(objPath); + LLVMArchive ar = TruffleLLVM_DLL.getZipLLVMIR(objPath); + LLVM_IR[] irs = ar.irs; if (irs == null) { System.out.printf("no llvm ir in %s\n", objPath); System.exit(1); diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java index ebefcef623..96e7f6e18b 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/upcalls/BytesToNativeCharArrayCallMR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java index 4c7f70db2c..92d7e73417 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/NativeStringCastNode.java @@ -1,3 +1,25 @@ +/* + * 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.nodes; import static com.oracle.truffle.r.runtime.data.NativeDataAccess.readNativeString; diff --git a/com.oracle.truffle.r.native/Makefile b/com.oracle.truffle.r.native/Makefile index 514fd0857f..159c2720d3 100644 --- a/com.oracle.truffle.r.native/Makefile +++ b/com.oracle.truffle.r.native/Makefile @@ -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 @@ -21,7 +21,7 @@ # questions. # -.PHONY: all clean +.PHONY: all clean export TOPDIR = $(CURDIR) export FASTR_R_HOME=$(abspath $(TOPDIR)/..) @@ -30,6 +30,15 @@ export FASTR_NATIVE_DIR = $(TOPDIR) export R_VERSION = 3.4.0 export GNUR_HOME = $(TOPDIR)/gnur/patch-build +ifeq ($(FASTR_RFFI),llvm) +ifndef FASTR_LLVM_TOOLS +ifdef FASTR_LLVM_FOR_DRAGONEGG_HOME +export FASTR_LLVM_TOOLS = $(FASTR_LLVM_FOR_DRAGONEGG_HOME)/bin +$(info FASTR_LLVM_TOOLS set to $(FASTR_LLVM_TOOLS)) +endif +endif +endif + $(info R_VERSION: $(R_VERSION)) $(info GNUR_HOME: $(GNUR_HOME)) @@ -43,7 +52,7 @@ $(info GNUR_HOME_BINARY not set. Assuming the default location at $(GNUR_HOME_BI endif # Completely accurate dependency analysis is very difficult for this project, so use a version number -# to force a clean build, and elsewhere use sentinels to avoid rebuilding when we can't compute the +# to force a clean build, and elsewhere use sentinels to avoid rebuilding when we can't compute the # dependencies accurately. all: checkversion @@ -54,7 +63,7 @@ all: checkversion $(MAKE) -C run cp version.source version.built -clean: +clean: $(MAKE) -C include clean $(MAKE) -C fficall clean $(MAKE) -C run clean diff --git a/com.oracle.truffle.r.native/fficall/Makefile b/com.oracle.truffle.r.native/fficall/Makefile index e22efe39d8..e6e0b6a202 100644 --- a/com.oracle.truffle.r.native/fficall/Makefile +++ b/com.oracle.truffle.r.native/fficall/Makefile @@ -80,12 +80,7 @@ fficall.done: common.done else ifeq ($(FASTR_RFFI),llvm) -ifndef FASTR_LLVM_TOOLS -ifdef FASTR_LLVM_FOR_DRAGONEGG_HOME -export FASTR_LLVM_TOOLS = $(FASTR_LLVM_FOR_DRAGONEGG_HOME)/bin -$(info FASTR_LLVM_TOOLS set to $(FASTR_LLVM_TOOLS)) -endif -endif +export R_PACKAGE_DIR="lib" fficall.done: common.done $(MAKE) -C src/truffle_llvm all touch fficall.done diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c index 680d13aaad..734c99bdd7 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c +++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/Memory.c @@ -5,7 +5,7 @@ * * Copyright (c) 1995-2015, 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. */ @@ -120,4 +120,3 @@ SEXP Rf_allocS4Object() { unimplemented("Rf_allocS4Object unimplemented"); return NULL; } - diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile b/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile index 7c53c00be0..6861f1ebc7 100644 --- a/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile +++ b/com.oracle.truffle.r.native/gnur/patch/src/library/Makefile @@ -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 @@ -25,6 +25,7 @@ SUBDIRS = base compiler datasets utils grDevices graphics grid parallel splines stats stats4 methods tools export FASTR_LIBRARY_DIR = $(abspath $(TOPDIR)/../library) +export R_PACKAGE_DIR="." all: libdir make_subdirs @@ -39,6 +40,6 @@ clean_subdirs: for dir in $(SUBDIRS); do \ $(MAKE) PACKAGE=$$dir -C $$dir clean || exit 1; \ done - + libdir: mkdir -p $(FASTR_LIBRARY_DIR) diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile index 20981356dc..ed0b9d2ac4 100644 --- a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile +++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/Makefile @@ -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 @@ -33,5 +33,4 @@ endif PKG_LIBS := $(LAPACK_LIBS) $(BLAS_LIBS) -L$(FASTR_LIB_DIR) $(FLIBS) PKG_INCLUDES = -I src - include ../lib.mk diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-c++ b/com.oracle.truffle.r.native/llvm_tools/llvm-c++ index a20027b69b..ec93f97e3d 100755 --- a/com.oracle.truffle.r.native/llvm_tools/llvm-c++ +++ b/com.oracle.truffle.r.native/llvm_tools/llvm-c++ @@ -33,7 +33,7 @@ if [ $is_link -eq 1 ] then extraObj="" if [ -f "$R_PACKAGE_DIR/libobjects" ]; then - extraObj=`cat $R_PACKAGE_DIR/libobjects` + extraObj=`cat "$R_PACKAGE_DIR/libobjects"` fi create_bc_lib $@ $extraObj else diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-cc b/com.oracle.truffle.r.native/llvm_tools/llvm-cc index 1ab1691aaa..42acf7a327 100755 --- a/com.oracle.truffle.r.native/llvm_tools/llvm-cc +++ b/com.oracle.truffle.r.native/llvm_tools/llvm-cc @@ -33,7 +33,7 @@ if [ $is_link -eq 1 ] then extraObj="" if [ -f "$R_PACKAGE_DIR/libobjects" ]; then - extraObj=`cat $R_PACKAGE_DIR/libobjects` + extraObj=`cat "$R_PACKAGE_DIR/libobjects"` fi create_bc_lib $@ $extraObj else diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-helper b/com.oracle.truffle.r.native/llvm_tools/llvm-helper index 88d41309ff..2f06ecefc7 100644 --- a/com.oracle.truffle.r.native/llvm_tools/llvm-helper +++ b/com.oracle.truffle.r.native/llvm_tools/llvm-helper @@ -132,25 +132,39 @@ function fake_obj() { function create_bc_lib() { bcfiles="" lib="" + statlibs="$R_PACKAGE_DIR/statlibs" + linkedLibs="LIBS" + > $linkedLibs while [[ $# -gt 0 ]] do case $1 in -o) shift - lib=$1 - ;; + lib=$1 + ;; + -l*) + linkedLib=`echo $1 | cut -c 3-` + statLibFound='0' + if [ -f "$statlibs" ]; then + statLibFound=`cat "$statlibs" | grep "lib${linkedLib}.a" | wc -l` + fi + if [ $statLibFound == '0' ] + then + echo $linkedLib >> $linkedLibs + fi + ;; -*) - # ignore options - ;; - *) + # ignore other options + ;; + *) f=$(basename $1) - ext=${f##*.} - if [ $ext == 'o' ] - then - fn="$(dirname $1)/${f%%.*}.bc" - bcfiles+="$fn " - fi - ;; + ext=${f##*.} + if [ $ext == 'o' ] + then + fn="$(dirname $1)/${f%%.*}.bc" + bcfiles+="$fn " + fi + ;; esac shift done @@ -161,8 +175,9 @@ function create_bc_lib() { # link the bitcode files into a single one using llvm-link before zipping it llvm_tool=llvm-link get_llvm_tool + echo "Linking $lib.bc from LLVM modules: $bcfiles" runit $llvm_tool_bin $bcfiles -o $lib.bc - runit zip -r $lib $lib.bc + runit zip -r $lib $lib.bc $linkedLibs rm $lib.bc } @@ -220,5 +235,8 @@ function create_bc_archive() { # Join the archived objects CSV with the unique symbols objects CSV to get the list of objects to be statically linked to the package dynamic library. # Append the result to the global list of extra object files. - join -t " " -1 1 -2 1 $archObjCSV $exportedObjCSV | awk -F ' ' '{print $2}' >> $R_PACKAGE_DIR/libobjects + join -t " " -1 1 -2 1 $archObjCSV $exportedObjCSV | awk -F ' ' '{print $2}' >> "$R_PACKAGE_DIR/libobjects" + + # Record the archive (static library) name to distinguish between LLVM static libs and native libs when linking (via -l) + echo $archname >> "$R_PACKAGE_DIR/statlibs" } 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 3b404e84df..09b82c05c4 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 @@ -114,6 +114,16 @@ public final class NativeDataAccess { */ private long length; + /** + * It maintains the <code>1-?</code> relationship between this object and its native wrapper + * through which the native code accesses it. For instance, Sulong implements the "pointer" + * equality of two objects that are not pointers (i.e. <code>IS_POINTER</code> returns + * <code>false</code>) as the reference equality of the objects. It follows that the pointer + * comparison would fail if the same <code>RObject</code> instance were wrapped by two + * different native wrappers. + */ + private Object nativeWrapper; + NativeMirror() { this.id = counter.incrementAndGet(); } @@ -204,8 +214,8 @@ public final class NativeDataAccess { if (arg instanceof RObject) { RObject obj = (RObject) arg; NativeMirror mirror = (NativeMirror) obj.getNativeMirror(); - if (mirror == null) { - mirror = putMirrorObject(arg, obj); + if (mirror == null || mirror.id == 0) { + mirror = putMirrorObject(arg, obj, mirror); } return mirror.id; } @@ -213,16 +223,19 @@ public final class NativeDataAccess { } @TruffleBoundary - private static NativeMirror putMirrorObject(Object arg, RObject obj) { - NativeMirror mirror; - obj.setNativeMirror(mirror = arg instanceof CustomNativeMirror ? new NativeMirror(((CustomNativeMirror) arg).getCustomMirrorAddress()) : new NativeMirror()); + private static NativeMirror putMirrorObject(Object arg, RObject obj, NativeMirror oldMirror) { + NativeMirror newMirror; + obj.setNativeMirror(newMirror = arg instanceof CustomNativeMirror ? new NativeMirror(((CustomNativeMirror) arg).getCustomMirrorAddress()) : new NativeMirror()); + if (oldMirror != null) { + newMirror.nativeWrapper = oldMirror.nativeWrapper; + } // System.out.println(String.format("adding %16x = %s", mirror.id, // obj.getClass().getSimpleName())); - nativeMirrors.put(mirror.id, new WeakReference<>(obj)); + nativeMirrors.put(newMirror.id, new WeakReference<>(obj)); if (TRACE_MIRROR_ALLOCATION_SITES) { - registerAllocationSite(arg, mirror); + registerAllocationSite(arg, newMirror); } - return mirror; + return newMirror; } @TruffleBoundary @@ -692,4 +705,23 @@ public final class NativeDataAccess { mirror.length = length; } + + public static void setNativeWrapper(RObject obj, Object wrapper) { + NativeMirror mirror = (NativeMirror) obj.getNativeMirror(); + if (mirror == null) { + mirror = new NativeMirror(0); + obj.setNativeMirror(mirror); + } + mirror.nativeWrapper = wrapper; + } + + public static Object getNativeWrapper(RObject obj) { + NativeMirror mirror = (NativeMirror) obj.getNativeMirror(); + if (mirror == null) { + return null; + } else { + return mirror.nativeWrapper; + } + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java index c4f8cdc520..d80f67f4bf 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObject.java @@ -25,15 +25,6 @@ package com.oracle.truffle.r.runtime.data; public abstract class RObject { private Object nativeMirror; - /** - * It maintains the <code>1-?</code> relationship between this object and its native wrapper - * through which the native code accesses it. For instance, Sulong implements the "pointer" - * equality of two objects that are not pointers (i.e. <code>IS_POINTER</code> returns - * <code>false</code>) as the reference equality of the objects. It follows that the pointer - * comparison would fail if the same <code>RObject</code> instance were wrapped by two different - * native wrappers. - */ - private Object nativeWrapper; public final void setNativeMirror(Object mirror) { this.nativeMirror = mirror; @@ -43,11 +34,4 @@ public abstract class RObject { return nativeMirror; } - public void setNativeWrapper(Object wrapper) { - this.nativeWrapper = wrapper; - } - - public Object getNativeWrapper() { - return this.nativeWrapper; - } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java index 86be2ec8d8..8ba6f70a6a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java @@ -48,8 +48,8 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra private Object car = RNull.instance; private Object cdr = RNull.instance; /** - * Externally, i.e., when serialized, this is either a SYMSXP ({@link RSymbol}) or an {@link RNull}. - * Internally it may take on other, non-null, values. + * Externally, i.e., when serialized, this is either a SYMSXP ({@link RSymbol}) or an + * {@link RNull}. Internally it may take on other, non-null, values. */ private Object tag = RNull.instance; -- GitLab