diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java index e5bb3244f4c3098f3746147634d6c4c26528fea1..2e79a9dca824e951df2c2e6317c473bda260b565 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Context.java @@ -29,10 +29,12 @@ import static com.oracle.truffle.r.ffi.impl.common.RFFIUtils.traceEnabled; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.EnumMap; +import java.util.concurrent.locks.ReentrantLock; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.Message; @@ -43,6 +45,7 @@ import com.oracle.truffle.r.ffi.impl.common.LibPaths; import com.oracle.truffle.r.ffi.impl.common.RFFIUtils; import com.oracle.truffle.r.ffi.impl.nfi.TruffleNFI_DLL.NFIHandle; import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks; +import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextKind; @@ -77,6 +80,9 @@ class UnsafeAdapter { final class TruffleNFI_Context extends RFFIContext { + @CompilationFinal private static boolean hasAccessLock; + private static ReentrantLock accessLock; + TruffleNFI_Context() { super(new TruffleNFI_C(), new TruffleNFI_Base(), new TruffleNFI_Call(), new TruffleNFI_DLL(), new TruffleNFI_UserRng(), new TruffleNFI_Zip(), new TruffleNFI_PCRE(), new TruffleNFI_Lapack(), new TruffleNFI_Stats(), new TruffleNFI_Tools(), new TruffleNFI_REmbed(), new TruffleNFI_Misc()); @@ -117,9 +123,17 @@ final class TruffleNFI_Context extends RFFIContext { if (function.getLibrary() == NativeFunction.baseLibrary()) { dllInfo = TruffleNFI_Context.getInstance().defaultLibrary; } else if (function.getLibrary() == NativeFunction.anyLibrary()) { - dllInfo = ((NFIHandle) DLL.findLibraryContainingSymbol(function.getCallName()).handle).libHandle; + DLLInfo lib = DLL.findLibraryContainingSymbol(function.getCallName()); + if (lib == null) { + throw RInternalError.shouldNotReachHere("Could not find library containing symbol " + function.getCallName()); + } + dllInfo = ((NFIHandle) lib.handle).libHandle; } else { - dllInfo = ((NFIHandle) DLL.findLibrary(function.getLibrary()).handle).libHandle; + DLLInfo lib = DLL.findLibrary(function.getLibrary()); + if (lib == null) { + throw RInternalError.shouldNotReachHere("Could not find library " + function.getLibrary()); + } + dllInfo = ((NFIHandle) lib.handle).libHandle; } try { TruffleObject symbol = ((TruffleObject) ForeignAccess.sendRead(Message.READ.createNode(), dllInfo, function.getCallName())); @@ -231,6 +245,7 @@ final class TruffleNFI_Context extends RFFIContext { @Override public ContextState initialize(RContext context) { RFFIUtils.initializeTracing(); + initializeLock(); if (traceEnabled()) { traceDownCall("initialize"); } @@ -266,6 +281,13 @@ final class TruffleNFI_Context extends RFFIContext { } } + private static synchronized void initializeLock() { + hasAccessLock = FastROptions.SynchronizeNativeCode.getBooleanValue(); + if (hasAccessLock && accessLock == null) { + accessLock = new ReentrantLock(); + } + } + @Override public void beforeDispose(RContext context) { switch (context.getKind()) { @@ -302,4 +324,30 @@ final class TruffleNFI_Context extends RFFIContext { public DLLInfo getRLibDLLInfo() { return rlibDLLInfo; } + + @Override + public void beforeUpcall(boolean canRunGc) { + super.beforeUpcall(canRunGc); + if (hasAccessLock) { + acquireLock(); + } + } + + @Override + public void afterUpcall(boolean canRunGc) { + super.afterUpcall(canRunGc); + if (hasAccessLock) { + releaseLock(); + } + } + + @TruffleBoundary + private void acquireLock() { + accessLock.lock(); + } + + @TruffleBoundary + private void releaseLock() { + accessLock.unlock(); + } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java index 688c3aa6344d79d994cf23b3fb4546485e4fe627..f914d4c94eca2392c4a0a0998e2fc0943cce1a09 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridContext.java @@ -50,8 +50,6 @@ import com.oracle.truffle.r.runtime.env.REnvironment; * Encapsulated the access to the global grid state. */ public final class GridContext { - private static final GridContext INSTANCE = new GridContext(); - private RInternalCode internalCode; private final GridState gridState = new GridState(); /** @@ -65,7 +63,11 @@ public final class GridContext { } public static GridContext getContext() { - return INSTANCE; + RContext rCtx = RContext.getInstance(); + if (rCtx.gridContext == null) { + rCtx.gridContext = new GridContext(); + } + return (GridContext) rCtx.gridContext; } @TruffleBoundary diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java index 651ec5ff1bdd5a59effb55fdf06d0fd1c2edac2c..9c2cce59df625173faf89f9847d7fe9208b3901e 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/RGridGraphicsAdapter.java @@ -24,6 +24,7 @@ import com.oracle.truffle.r.runtime.ROptions.OptionsException; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -65,7 +66,7 @@ public final class RGridGraphicsAdapter { } public static void initialize() { - addDevice(NULL_DEVICE); + REnvironment.baseEnv().safePut(DOT_DEVICES, RDataFactory.createPairList(NULL_DEVICE)); setCurrentDevice(NULL_DEVICE); RContext ctx = RContext.getInstance(); ROptions.ContextStateImpl options = ctx.stateROptions; @@ -81,26 +82,41 @@ public final class RGridGraphicsAdapter { } /** - * Fixup .Devices array as someone may have set it to something that is not a pair list nor - * RNull, which breaks dev.cur built-in R function and others. GNUR seems to have active binding - * for it. This is such special case that it doesn't seem necessary for now. + * Fixup .Devices global variable to be a pair list of length at least 1. Non-empty lists are + * converted to pair lists, anything else causes the variable to be reset back to the initial + * value. */ @TruffleBoundary - public static void fixupDevicesVariable() { - Object devices = REnvironment.baseEnv().get(DOT_DEVICES); - if (devices == RNull.instance || !(devices instanceof RPairList)) { - // reset the .Devices and .Device variables to initial values - REnvironment.baseEnv().safePut(DOT_DEVICES, RNull.instance); - addDevice(NULL_DEVICE); - setCurrentDevice(NULL_DEVICE); + public static RPairList fixupDevicesVariable() { + REnvironment baseEnv = REnvironment.baseEnv(); + Object devices = baseEnv.get(DOT_DEVICES); + if (devices instanceof RPairList) { + return (RPairList) devices; + } + if (devices instanceof RList) { + RList list = (RList) devices; + if (list.getLength() > 0) { + RPairList head = RDataFactory.createPairList(list.getDataAt(0)); + RPairList curr = head; + for (int i = 1; i < list.getLength(); i++) { + RPairList next = RDataFactory.createPairList(list.getDataAt(i)); + curr.setCdr(next); + curr = next; + } + baseEnv.safePut(DOT_DEVICES, head); + return head; + } } + // reset the .Devices and .Device variables to initial values + RPairList nullDevice = RDataFactory.createPairList(NULL_DEVICE); + baseEnv.safePut(DOT_DEVICES, nullDevice); + setCurrentDevice(NULL_DEVICE); + return nullDevice; } public static void removeDevice(int index) { assert index > 0 : "cannot remove null device"; - REnvironment baseEnv = REnvironment.baseEnv(); - fixupDevicesVariable(); - RPairList devices = (RPairList) baseEnv.get(DOT_DEVICES); + RPairList devices = fixupDevicesVariable(); assert index < devices.getLength() : "wrong index in removeDevice"; RPairList prev = devices; for (int i = 0; i < index - 1; ++i) { @@ -120,12 +136,8 @@ public final class RGridGraphicsAdapter { public static void addDevice(String name) { REnvironment baseEnv = REnvironment.baseEnv(); baseEnv.safePut(DOT_DEVICE, name); - Object dotDevices = baseEnv.get(DOT_DEVICES); - if (dotDevices instanceof RPairList) { - ((RPairList) dotDevices).appendToEnd(RDataFactory.createPairList(name)); - } else { - baseEnv.safePut(DOT_DEVICES, RDataFactory.createPairList(name)); - } + RPairList dotDevices = fixupDevicesVariable(); + dotDevices.appendToEnd(RDataFactory.createPairList(name)); } public static String getDefaultDevice() { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java index 982d68f8efb80f69c549df0d455d1b7be7985137..090cd5aa987d71ee1ac1da2c7155bc2e7643cdd2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java @@ -61,6 +61,7 @@ public enum FastROptions { EmitTmpDir("The directory where to allocate temporary files with deparsed source code.", null, true), EmitTmpHashed("Use an SHA-256 hash as file name to reduce temporary file creation.", true), SpawnUsesPolyglot("use PolyglotEngine for .fastr.context.spwan", false), + SynchronizeNativeCode("allow only one thread to enter packages' native code", false), // Promises optimizations EagerEval("If enabled, overrides all other EagerEval switches (see EagerEvalHelper)", false), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index 6de77baa7e43dbc7c86d6b2b19189aae6815a519..8af2341afbf9fb09911971519bb828c0cf4cb103 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -350,6 +350,10 @@ public final class RContext implements RTruffleObject { @CompilationFinal private RFFIContext stateRFFI; + // Context specific state required for libraries, the initialization is handled lazily by the + // concrete library. + public Object gridContext = null; + public final WeakHashMap<String, WeakReference<String>> stringMap = new WeakHashMap<>(); public final WeakHashMap<Source, REnvironment> sourceRefEnvironments = new WeakHashMap<>(); public final WeakHashMap<Path, REnvironment> srcfileEnvironments = new WeakHashMap<>(); 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 94db655cbf26e41ce2bd67c199bd8cf7e0bec360..6c9a027c498ee7598fc01ac60707f02d68665e2e 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 @@ -654,7 +654,7 @@ public class DLL { return findSymbolNode.execute((String) args[0], (String) args[1], (RegisteredNativeSymbol) args[2]); } - private static RFindSymbolRootNode create() { + private static synchronized RFindSymbolRootNode create() { if (findSymbolRootNode == null) { findSymbolRootNode = new RFindSymbolRootNode(); Truffle.getRuntime().createCallTarget(findSymbolRootNode);