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);