diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
index 7a04b504b11329490bd1dde0ac648031954f2576..4a5c2c8f91d39546e12aa5cc50e323144834cb3a 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java
@@ -77,13 +77,13 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
             RVersionInfo.initialize();
             TempPathName.initialize();
             RPackageSource.initialize();
-            RContext.initialize(new RASTBuilder(), new RRuntimeASTAccessImpl(), RBuiltinPackages.getInstance(), new RForeignAccessFactoryImpl());
+
         } catch (Throwable t) {
             Utils.rSuicide("error during R language initialization");
         }
     }
 
-    private static boolean initialized;
+    private static boolean systemInitialized;
 
     public static final TruffleRLanguage INSTANCE = new TruffleRLanguage();
 
@@ -98,12 +98,20 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> {
     }
 
     @Override
-    protected RContext createContext(Env env) {
-        boolean initialContext = !initialized;
-        if (!initialized) {
+    protected void initializeContext(RContext context) throws Exception {
+        if (!systemInitialized) {
             FastROptions.initialize();
             initialize();
-            initialized = true;
+            systemInitialized = true;
+        }
+        context.initializeContext();
+    }
+
+    @Override
+    protected RContext createContext(Env env) {
+        boolean initialContext = !systemInitialized;
+        if (initialContext) {
+            RContext.initializeGlobalState(new RASTBuilder(), new RRuntimeASTAccessImpl(), RBuiltinPackages.getInstance(), new RForeignAccessFactoryImpl());
         }
         RContext result = RContext.create(env, env.lookup(Instrumenter.class), initialContext);
         return result;
diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
index da24f27db4ab82bba8840d97541dffae4e408e88..05a093a010bd91d13ab53b115f77be56f86458b5 100644
--- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java
@@ -83,7 +83,7 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI {
     }
 
     @Override
-    public ContextState newContext(RContext context) {
+    public ContextState newContextState() {
         return new ContextStateImpl();
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyDBCache.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyDBCache.java
index ab4b19c7e04187feceb1d8cc9126307e2b2611f3..6b742edcf91819f1db05231372d374d31af946cf 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyDBCache.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyDBCache.java
@@ -54,7 +54,7 @@ public class LazyDBCache {
             dbCache.remove(dbPath);
         }
 
-        public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) {
+        public static ContextStateImpl newContextState() {
             return new ContextStateImpl();
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
index e8d68692064e190abdaae38f28d52c457d599a63..de47b4ddec697922b22eccb5fa005ce733d6ecba 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
@@ -45,7 +45,11 @@ public final class REnvVars implements RContext.ContextState {
 
     private final Map<String, String> envVars = new HashMap<>(System.getenv());
 
-    private REnvVars(RContext context) {
+    private REnvVars() {
+    }
+
+    @Override
+    public RContext.ContextState initialize(RContext context) {
         // set the standard vars defined by R
         String rHome = System.getenv("R_HOME");
         // Always read the system file
@@ -101,10 +105,11 @@ public final class REnvVars implements RContext.ContextState {
                 System.setProperty("http.proxyPort", port);
             }
         }
+        return this;
     }
 
-    public static REnvVars newContext(RContext context) {
-        return new REnvVars(context);
+    public static REnvVars newContextState() {
+        return new REnvVars();
     }
 
     private String getEitherCase(String var) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
index 74aff0e6602d52b7bdc9cc54b91f01276aa6dd41..99b9a1969db1af9fc24e57c193d6a551cf599469 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java
@@ -145,7 +145,7 @@ public class RErrorHandling {
             return dotSignalSimpleWarning;
         }
 
-        public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) {
+        public static ContextStateImpl newContextState() {
             return new ContextStateImpl();
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java
index 7c13688fa10cb3e0cd412936cccd1d5f64de82bd..05c5cfbc2cd2bf86b593119f905138179d375fd7 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalCode.java
@@ -104,7 +104,7 @@ public final class RInternalCode {
             codes.put(source, code);
         }
 
-        public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) {
+        public static ContextStateImpl newContextState() {
             return new ContextStateImpl();
         }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
index 997c7ea8691a5f47e26a9849b0d87fe527ad1673..05c614c25acbde2a40fb38145f061baccf255cd9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ROptions.java
@@ -51,9 +51,11 @@ public class ROptions {
          * The current values for a given context.
          */
         private final HashMap<String, Object> map;
+        private final REnvVars envVars;
 
-        private ContextStateImpl(HashMap<String, Object> map) {
+        private ContextStateImpl(HashMap<String, Object> map, REnvVars envVars) {
             this.map = map;
+            this.envVars = envVars;
             // cannot call updateDotOptions here
         }
 
@@ -95,14 +97,19 @@ public class ROptions {
         }
 
         @TruffleBoundary
-        public static ContextStateImpl newContext(RContext context, REnvVars envVars) {
+        public static ContextStateImpl newContextState(REnvVars envVars) {
             HashMap<String, Object> map = new HashMap<>();
+            return new ContextStateImpl(map, envVars);
+        }
+
+        @Override
+        public RContext.ContextState initialize(RContext context) {
             if (context.getKind() == ContextKind.SHARE_NOTHING) {
                 applyDefaults(map, context.getStartParams(), envVars);
             } else {
                 map.putAll(context.getParent().stateROptions.map);
             }
-            return new ContextStateImpl(map);
+            return this;
         }
 
         /**
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
index 2522a7fbeeea4765c298c3010b875d219369c949..3af2daa50e1ea8b7403d0e223a2bc9e9ddf3bfbf 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RProfile.java
@@ -38,7 +38,14 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
  */
 public final class RProfile implements RContext.ContextState {
 
-    private RProfile(RContext context, REnvVars envVars) {
+    private final REnvVars envVars;
+
+    private RProfile(REnvVars envVars) {
+        this.envVars = envVars;
+    }
+
+    @Override
+    public RContext.ContextState initialize(RContext context) {
         String rHome = REnvVars.rHome();
         FileSystem fileSystem = FileSystems.getDefault();
         Source newSiteProfile = null;
@@ -77,10 +84,11 @@ public final class RProfile implements RContext.ContextState {
         }
         siteProfile = newSiteProfile;
         userProfile = newUserProfile;
+        return this;
     }
 
-    private final Source siteProfile;
-    private final Source userProfile;
+    private Source siteProfile;
+    private Source userProfile;
 
     public static Source systemProfile() {
         Path path = FileSystems.getDefault().getPath(REnvVars.rHome(), "library", "base", "R", "Rprofile");
@@ -108,7 +116,7 @@ public final class RProfile implements RContext.ContextState {
         }
     }
 
-    public static RProfile newContext(RContext context, REnvVars envVars) {
-        return new RProfile(context, envVars);
+    public static RProfile newContextState(REnvVars envVars) {
+        return new RProfile(envVars);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index ea78607cbe02b1536e9fe56808bce31c3476fb65..8b542782abfdb264abf66b38f53af7728f35310b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -201,7 +201,7 @@ public class RSerialize {
             return dotDotFindNamespace;
         }
 
-        public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) {
+        public static ContextStateImpl newContextState() {
             return new ContextStateImpl();
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java
index 58a135e705e73f61cd5b64a1d618a6887615c5dd..94bbb2c406c799f13df7f27a6e06e0d27c4c9e49 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java
@@ -179,7 +179,7 @@ public class ConnectionSupport {
             }
         }
 
-        public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) {
+        public static ContextStateImpl newContextState() {
             return new ContextStateImpl();
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java
index a8436ff49f669512583d889c7190c43352383dd5..22f8ca5d238f1834edc99797045c60ffdbac47c8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java
@@ -51,25 +51,27 @@ public class StdConnections {
     }
 
     public static final class ContextStateImpl implements RContext.ContextState {
-        private final StdinConnection stdin;
-        private final StdoutConnection stdout;
-        private final StderrConnection stderr;
+        private StdinConnection stdin;
+        private StdoutConnection stdout;
+        private StderrConnection stderr;
         private final Diversion[] diversions = new Diversion[20];
         private int top = -1;
 
-        private ContextStateImpl(StdinConnection stdin, StdoutConnection stdout, StderrConnection stderr) {
-            this.stdin = stdin;
-            this.stdout = stdout;
-            this.stderr = stderr;
+        public static ContextStateImpl newContextState() {
+            return new ContextStateImpl();
         }
 
-        public static ContextStateImpl newContext(RContext context) {
+        @Override
+        public RContext.ContextState initialize(RContext context) {
             ConsoleHandler consoleHandler = context.getConsoleHandler();
             try {
-                return new ContextStateImpl(new StdinConnection(), new StdoutConnection(consoleHandler), new StderrConnection(consoleHandler));
+                stdin = new StdinConnection();
+                stdout = new StdoutConnection(consoleHandler);
+                stderr = new StderrConnection(consoleHandler);
             } catch (IOException ex) {
                 throw Utils.rSuicide("failed to open stdconnections:");
             }
+            return this;
         }
     }
 
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 80111d53d511755e0c67b05f74c6dbaf75a8d96f..d6c5f4000b239b4ca1ac3fba0486ffdfe6ac5a01 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
@@ -33,6 +33,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.ExecutionContext;
 import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.TruffleLanguage.Env;
 import com.oracle.truffle.api.instrumentation.Instrumenter;
 import com.oracle.truffle.api.interop.ForeignAccess;
@@ -143,6 +144,15 @@ public final class RContext extends ExecutionContext implements TruffleObject {
      * interface.
      */
     public interface ContextState {
+        /**
+         * Initialize the state. The initial creation should involve minimal computation; any
+         * significant computation should be handled in this method.
+         */
+        @SuppressWarnings("unused")
+        default ContextState initialize(RContext context) {
+            return this;
+        }
+
         /**
          * Called in response to the {@link RContext#destroy} method. Provides a hook for finalizing
          * any state before the context is destroyed.
@@ -333,7 +343,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
     /**
      * Initialize VM-wide static values.
      */
-    public static void initialize(RCodeBuilder<RSyntaxNode> rAstBuilder, RRuntimeASTAccess rRuntimeASTAccess, RBuiltinLookup rBuiltinLookup, RForeignAccessFactory rForeignAccessFactory) {
+    public static void initializeGlobalState(RCodeBuilder<RSyntaxNode> rAstBuilder, RRuntimeASTAccess rRuntimeASTAccess, RBuiltinLookup rBuiltinLookup, RForeignAccessFactory rForeignAccessFactory) {
         RContext.astBuilder = rAstBuilder;
         RContext.runtimeASTAccess = rRuntimeASTAccess;
         RContext.builtinLookup = rBuiltinLookup;
@@ -368,19 +378,23 @@ public final class RContext extends ExecutionContext implements TruffleObject {
      * could do this more dynamically with a registration process, perhaps driven by an annotation
      * processor, but the set is relatively small, so we just enumerate them here.
      */
-    public REnvVars stateREnvVars;
-    public RProfile stateRProfile;
-    public ROptions.ContextStateImpl stateROptions;
+    public final REnvVars stateREnvVars;
+    public final RProfile stateRProfile;
+    public final StdConnections.ContextStateImpl stateStdConnections;
+    public final ROptions.ContextStateImpl stateROptions;
     public final REnvironment.ContextStateImpl stateREnvironment;
     public final RErrorHandling.ContextStateImpl stateRErrorHandling;
     public final ConnectionSupport.ContextStateImpl stateRConnection;
-    public final StdConnections.ContextStateImpl stateStdConnections;
     public final RRNG.ContextStateImpl stateRNG;
-    public final ContextState stateRFFI;
     public final RSerialize.ContextStateImpl stateRSerialize;
     public final LazyDBCache.ContextStateImpl stateLazyDBCache;
     public final InstrumentationState stateInstrumentation;
     public final ContextStateImpl stateInternalCode;
+    /**
+     * RFFI implementation state. Cannot be final as choice of FFI implementation is not made at the
+     * time the constructor is called.
+     */
+    private ContextState stateRFFI;
 
     private ContextState[] contextStates() {
         return new ContextState[]{stateREnvVars, stateRProfile, stateROptions, stateREnvironment, stateRErrorHandling, stateRConnection, stateStdConnections, stateRNG, stateRFFI, stateRSerialize,
@@ -395,6 +409,13 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         return embedded;
     }
 
+    /**
+     * Sets the fields that do not depend on complex initialization.
+     *
+     * @param env values passed from {@link TruffleLanguage#createContext}
+     * @param instrumenter value passed from {@link TruffleLanguage#createContext}
+     * @param isInitial {@code true} if this is the initial (primordial) context.
+     */
     private RContext(Env env, Instrumenter instrumenter, boolean isInitial) {
         ContextInfo initialInfo = (ContextInfo) env.importSymbol(ContextInfo.GLOBAL_SYMBOL);
         if (initialInfo == null) {
@@ -408,7 +429,27 @@ public final class RContext extends ExecutionContext implements TruffleObject {
             this.info = initialInfo;
         }
         this.initial = isInitial;
+        this.env = env;
+        this.stateREnvVars = REnvVars.newContextState();
+        this.stateROptions = ROptions.ContextStateImpl.newContextState(stateREnvVars);
+        this.stateRProfile = RProfile.newContextState(stateREnvVars);
+        this.stateStdConnections = StdConnections.ContextStateImpl.newContextState();
+        this.stateREnvironment = REnvironment.ContextStateImpl.newContextState();
+        this.stateRErrorHandling = RErrorHandling.ContextStateImpl.newContextState();
+        this.stateRConnection = ConnectionSupport.ContextStateImpl.newContextState();
+        this.stateRNG = RRNG.ContextStateImpl.newContextState();
+        this.stateRSerialize = RSerialize.ContextStateImpl.newContextState();
+        this.stateLazyDBCache = LazyDBCache.ContextStateImpl.newContextState();
+        this.stateInstrumentation = InstrumentationState.newContextState(instrumenter);
+        this.stateInternalCode = ContextStateImpl.newContextState();
+        this.engine = RContext.getRRuntimeASTAccess().createEngine(this);
+    }
 
+    /**
+     * Performs the real initialization of the context, invoked from
+     * {@link TruffleLanguage#initializeContext}.
+     */
+    public RContext initializeContext() {
         // this must happen before engine activation in the code below
         if (info.getKind() == ContextKind.SHARE_NOTHING) {
             if (info.getParent() == null) {
@@ -423,7 +464,6 @@ public final class RContext extends ExecutionContext implements TruffleObject {
             }
         }
 
-        this.env = env;
         if (info.getConsoleHandler() == null) {
             throw Utils.rSuicide("no console handler set");
         }
@@ -436,7 +476,6 @@ public final class RContext extends ExecutionContext implements TruffleObject {
                 singleContextAssumption.invalidate();
             }
         }
-        engine = RContext.getRRuntimeASTAccess().createEngine(this);
 
         /*
          * Activate the context by attaching the current thread and initializing the {@link
@@ -453,16 +492,19 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         if (!embedded) {
             doEnvOptionsProfileInitialization();
         }
-        stateREnvironment = REnvironment.ContextStateImpl.newContext(this);
-        stateRErrorHandling = RErrorHandling.ContextStateImpl.newContext(this);
-        stateRConnection = ConnectionSupport.ContextStateImpl.newContext(this);
-        stateStdConnections = StdConnections.ContextStateImpl.newContext(this);
-        stateRNG = RRNG.ContextStateImpl.newContext(this);
-        stateRFFI = RFFIContextStateFactory.newContext(this);
-        stateRSerialize = RSerialize.ContextStateImpl.newContext(this);
-        stateLazyDBCache = LazyDBCache.ContextStateImpl.newContext(this);
-        stateInstrumentation = InstrumentationState.newContext(this, instrumenter);
-        stateInternalCode = ContextStateImpl.newContext(this);
+
+        stateREnvironment.initialize(this);
+        stateRErrorHandling.initialize(this);
+        stateRConnection.initialize(this);
+        stateStdConnections.initialize(this);
+        stateRNG.initialize(this);
+        this.stateRFFI = RFFIContextStateFactory.newContextState().initialize(this);
+
+        stateRFFI.initialize(this);
+        stateRSerialize.initialize(this);
+        stateLazyDBCache.initialize(this);
+        stateInstrumentation.initialize(this);
+        stateInternalCode.initialize(this);
 
         if (!embedded) {
             validateContextStates();
@@ -478,20 +520,21 @@ public final class RContext extends ExecutionContext implements TruffleObject {
             // that methods package is loaded
             this.methodTableDispatchOn = info.getParent().methodTableDispatchOn;
         }
-        if (isInitial && !embedded) {
+        if (initial && !embedded) {
             RFFIFactory.getRFFI().getCallRFFI().setInteractive(isInteractive());
             initialContextInitialized = true;
         }
+        return this;
     }
 
     /**
      * Factored out for embedded setup, where this initialization may be customized after the
-     * context is created but before VM really starts execution.
+     * context is initialized but before VM really starts execution.
      */
     private void doEnvOptionsProfileInitialization() {
-        stateREnvVars = REnvVars.newContext(this);
-        stateROptions = ROptions.ContextStateImpl.newContext(this, stateREnvVars);
-        stateRProfile = RProfile.newContext(this, stateREnvVars);
+        stateREnvVars.initialize(this);
+        stateROptions.initialize(this);
+        stateRProfile.initialize(this);
     }
 
     public void completeEmbeddedInitialization() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
index e66aef15b5c364f8e2fc610525b1286ef902d4f1..00915a63c5d58c85b0adbe9cbf693ae780de7acb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
@@ -100,7 +100,7 @@ import com.oracle.truffle.r.runtime.env.frame.REnvTruffleFrameAccess;
  * <p>
  * The logic for implementing the three different forms of
  * {@link com.oracle.truffle.r.runtime.context.RContext.ContextKind} is encapsulated in the
- * {@link #createContext} method.
+ * {@link #setupContext} method.
  */
 public abstract class REnvironment extends RAttributeStorage {
 
@@ -118,15 +118,18 @@ public abstract class REnvironment extends RAttributeStorage {
         private REnvironment namespaceRegistry;
         private MaterializedFrame parentGlobalFrame; // SHARED_PARENT_RW only
 
-        ContextStateImpl(MaterializedFrame globalFrame, SearchPath searchPath) {
+        private ContextStateImpl(MaterializedFrame globalFrame) {
             this.globalFrame = globalFrame;
-            this.searchPath = searchPath;
         }
 
-        ContextStateImpl(MaterializedFrame globalFrame, SearchPath searchPath, Base baseEnv, REnvironment namespaceRegistry) {
-            this(globalFrame, searchPath);
-            this.baseEnv = baseEnv;
-            this.namespaceRegistry = namespaceRegistry;
+        private void initialize(SearchPath searchPathA) {
+            this.searchPath = searchPathA;
+        }
+
+        private void initialize(SearchPath searchPathA, Base baseEnvA, REnvironment namespaceRegistryA) {
+            this.searchPath = searchPathA;
+            this.baseEnv = baseEnvA;
+            this.namespaceRegistry = namespaceRegistryA;
         }
 
         public REnvironment getGlobalEnv() {
@@ -165,13 +168,20 @@ public abstract class REnvironment extends RAttributeStorage {
             this.namespaceRegistry = namespaceRegistry;
         }
 
+        @Override
+        public RContext.ContextState initialize(RContext context) {
+            setupContext(this, context, globalFrame);
+            return this;
+
+        }
+
         @Override
         public void beforeDestroy(RContext context) {
             beforeDestroyContext(context, this);
         }
 
-        public static ContextStateImpl newContext(RContext context) {
-            return createContext(context, RRuntime.createNonFunctionFrame("global"));
+        public static ContextStateImpl newContextState() {
+            return new ContextStateImpl(RRuntime.createNonFunctionFrame("global"));
         }
     }
 
@@ -311,7 +321,7 @@ public abstract class REnvironment extends RAttributeStorage {
      * N.B. {@link RContext#stateREnvironment} accesses the new, as yet uninitialized
      * {@link ContextStateImpl} object
      */
-    private static ContextStateImpl createContext(RContext context, MaterializedFrame globalFrame) {
+    private static void setupContext(ContextStateImpl contextState, RContext context, MaterializedFrame globalFrame) {
         switch (context.getKind()) {
             case SHARE_PARENT_RW: {
                 /*
@@ -331,9 +341,9 @@ public abstract class REnvironment extends RAttributeStorage {
                 SearchPath searchPath = initSearchList(prevGlobalEnv);
                 searchPath.updateGlobal(newGlobalEnv);
                 parentState.getBaseEnv().safePut(".GlobalEnv", newGlobalEnv);
-                ContextStateImpl result = new ContextStateImpl(globalFrame, searchPath, parentBaseEnv, parentState.getNamespaceRegistry());
-                result.parentGlobalFrame = prevGlobalFrame;
-                return result;
+                contextState.initialize(searchPath, parentBaseEnv, parentState.getNamespaceRegistry());
+                contextState.parentGlobalFrame = prevGlobalFrame;
+                break;
             }
 
             case SHARE_PARENT_RO: {
@@ -359,12 +369,14 @@ public abstract class REnvironment extends RAttributeStorage {
                 newNamespaceRegistry.safePut("base", newBaseEnv.namespaceEnv);
                 newBaseEnv.safePut(".GlobalEnv", newGlobalEnv);
                 SearchPath newSearchPath = initSearchList(newGlobalEnv);
-                return new ContextStateImpl(globalFrame, newSearchPath, newBaseEnv, newNamespaceRegistry);
+                contextState.initialize(newSearchPath, newBaseEnv, newNamespaceRegistry);
+                break;
             }
 
             case SHARE_NOTHING: {
                 // SHARE_NOTHING: baseInitialize takes care of everything
-                return new ContextStateImpl(globalFrame, new SearchPath());
+                contextState.initialize(new SearchPath());
+                break;
             }
 
             default:
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java
index f18abc1221f6e63e44c8e67e04ee2f18e95cfd49..934ad58e5ef650278cab6880dc4afc692cf5c19a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContextStateFactory.java
@@ -37,7 +37,7 @@ public class RFFIContextStateFactory {
         theFactory = factory;
     }
 
-    public static ContextState newContext(RContext context) {
-        return theFactory.newContext(context);
+    public static ContextState newContextState() {
+        return theFactory.newContextState();
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
index cdbe8d0b82ad6d03f6e2848499ccc4550be3d3d0..c20087b3659bc3ec93056bf5704afe7a88eb2ae3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java
@@ -32,7 +32,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextState;
  * choice of factory is made by the R engine and set here by the call to {@link #setRFFIFactory}.
  *
  * The RFFI may need to do special things in the case of multiple contexts, hence any given factory
- * must support the {@link #newContext(RContext)} method. However, since we don't know exactly which
+ * must support the {@link #newContextState()} method. However, since we don't know exactly which
  * factory will be used, {@link RContext} references the {@link RFFIContextStateFactory} class.
  */
 public abstract class RFFIFactory {
@@ -110,5 +110,5 @@ public abstract class RFFIFactory {
         throw Utils.rSuicide(ffi + " FFI not implemented");
     }
 
-    public abstract ContextState newContext(RContext context);
+    public abstract ContextState newContextState();
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java
index b1a55172ce2f496442b27013b8366f929c0f189e..4af3bde56a12da075ef32fb01242f384c846c925 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java
@@ -278,7 +278,7 @@ public final class InstrumentationState implements RContext.ContextState {
         return debugGloballyDisabled;
     }
 
-    public static InstrumentationState newContext(@SuppressWarnings("unused") RContext context, Instrumenter instrumenter) {
+    public static InstrumentationState newContextState(Instrumenter instrumenter) {
         return new InstrumentationState(instrumenter);
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
index e612d30596a030b05daff37419470273f2a8d898..88742c519159680226051c8df374addd89f4e25f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
@@ -128,11 +128,19 @@ public class RRNG {
         private final RandomNumberGenerator[] allGenerators;
         private NormKind currentNormKind;
 
-        private ContextStateImpl(RandomNumberGenerator rng, NormKind currentNormKind) {
-            this.currentGenerator = rng;
-            this.currentNormKind = currentNormKind;
+        private ContextStateImpl() {
+            this.currentNormKind = DEFAULT_NORM_KIND;
             this.allGenerators = new RandomNumberGenerator[Kind.VALUES.length];
+        }
+
+        @Override
+        public RContext.ContextState initialize(RContext context) {
+            int seed = timeToSeed();
+            RandomNumberGenerator rng = DEFAULT_KIND.create();
+            initGenerator(rng, seed);
+            this.currentGenerator = rng;
             this.allGenerators[rng.getKind().ordinal()] = rng;
+            return this;
         }
 
         /*
@@ -180,11 +188,8 @@ public class RRNG {
             }
         }
 
-        public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) {
-            int seed = timeToSeed();
-            RandomNumberGenerator rng = DEFAULT_KIND.create();
-            initGenerator(rng, seed);
-            return new ContextStateImpl(rng, DEFAULT_NORM_KIND);
+        public static ContextStateImpl newContextState() {
+            return new ContextStateImpl();
         }
 
     }