diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
index c1bc7253e3734145ae3e0e57a2c8927f41f6cbe0..4dabafd7787fd836664697b4e600e68c6e29ece2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OnExit.java
@@ -44,6 +44,7 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPromise;
+import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.env.frame.RFrameSlot;
 
 @RBuiltin(name = "on.exit", visibility = OFF, kind = PRIMITIVE, parameterNames = {"expr", "add"}, nonEvalArgs = 0, behavior = COMPLEX)
@@ -71,7 +72,7 @@ public abstract class OnExit extends RBuiltinNode.Arg2 {
 
         if (onExitSlot == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            onExitSlot = frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.OnExit, FrameSlotKind.Object);
+            onExitSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RFrameSlot.OnExit, FrameSlotKind.Object);
         }
 
         // the empty (RNull.instance) expression is used to clear on.exit
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
index 25883797eef9b10da63e2df558e92940ffeafdf3..c59f4dbc43c325a0046106d0e04140d1123b77f4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.builtin.fastr;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.equalTo;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gt;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement;
@@ -42,6 +41,7 @@ import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RChannel;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RError;
@@ -50,6 +50,8 @@ import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.ContextInfo;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
+import com.oracle.truffle.r.runtime.context.RContext.EvalThread;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -57,6 +59,7 @@ import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 
 /**
  * The FastR builtins that allow multiple "virtual" R sessions potentially executing in parallel.
@@ -70,11 +73,8 @@ public class FastRContext {
 
         private static void kind(Casts casts) {
             casts.arg("kind").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst().mustNotBeNA().mustBe(
-                            equalTo(RContext.ContextKind.SHARE_NOTHING.name()).or(equalTo(RContext.ContextKind.SHARE_PARENT_RW.name()).or(equalTo(RContext.ContextKind.SHARE_PARENT_RO.name()))));
-        }
-
-        private static void pc(Casts casts) {
-            casts.arg("pc").asIntegerVector().findFirst().mustNotBeNA().mustBe(gt(0));
+                            equalTo(RContext.ContextKind.SHARE_NOTHING.name()).or(equalTo(RContext.ContextKind.SHARE_PARENT_RW.name()).or(
+                                            equalTo(RContext.ContextKind.SHARE_PARENT_RO.name()).or(equalTo(RContext.ContextKind.SHARE_ALL.name())))));
         }
 
         private static void key(Casts casts) {
@@ -95,40 +95,62 @@ public class FastRContext {
         }
     }
 
+    private static void handleSharedContexts(ContextKind contextKind) {
+        if (contextKind == ContextKind.SHARE_ALL) {
+            RContext current = RContext.getInstance();
+            if (EvalThread.threads.size() == 0 && (current.isInitial() || current.getKind() == ContextKind.SHARE_PARENT_RW)) {
+                ContextInfo.resetMultiSlotIndexGenerator();
+            } else {
+                throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, "Shared contexts can be created only if no other child contexts exist");
+            }
+        }
+    }
+
     /**
      * Similar to {@code .fastr.context.eval} but the invoking thread does not wait for completion,
      * which is done by {@code .fastr.context.join}. The result is a vector that should be passed to
      * {@code .fastr.context.join}.
      *
      */
-    @RBuiltin(name = ".fastr.context.spawn", kind = PRIMITIVE, parameterNames = {"exprs", "pc", "kind"}, behavior = COMPLEX)
-    public abstract static class Spawn extends RBuiltinNode.Arg3 {
+    @RBuiltin(name = ".fastr.context.spawn", kind = PRIMITIVE, parameterNames = {"exprs", "kind"}, behavior = COMPLEX)
+    public abstract static class Spawn extends RBuiltinNode.Arg2 {
         @Override
         public Object[] getDefaultParameterValues() {
-            return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
+            return new Object[]{RMissing.instance, FastROptions.SharedContexts.getBooleanValue() ? "SHARE_ALL" : "SHARE_NOTHING"};
         }
 
         static {
             Casts casts = new Casts(Spawn.class);
             CastsHelper.exprs(casts);
-            CastsHelper.pc(casts);
             CastsHelper.kind(casts);
         }
 
         @Specialization
         @TruffleBoundary
-        protected RIntVector spawn(RAbstractStringVector exprs, int pc, String kind) {
+        protected RIntVector spawn(RAbstractStringVector exprs, String kind) {
             RContext.ContextKind contextKind = RContext.ContextKind.valueOf(kind);
-            RContext.EvalThread[] threads = new RContext.EvalThread[pc];
-            int[] data = new int[pc];
-            for (int i = 0; i < pc; i++) {
+            if (FastROptions.SharedContexts.getBooleanValue() && contextKind != ContextKind.SHARE_ALL) {
+                throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, "Only shared contexts are allowed");
+            }
+            handleSharedContexts(contextKind);
+
+            int length = exprs.getLength();
+            RContext.EvalThread[] threads = new RContext.EvalThread[length];
+            int[] data = new int[length];
+            for (int i = 0; i < length; i++) {
                 ContextInfo info = createContextInfo(contextKind);
-                threads[i] = new RContext.EvalThread(info, RSource.fromTextInternal(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL));
+                threads[i] = new RContext.EvalThread(info, RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL));
                 data[i] = info.getId();
             }
-            for (int i = 0; i < pc; i++) {
+            if (contextKind == ContextKind.SHARE_ALL) {
+                REnvironment.convertSearchpathToMultiSlot();
+            }
+            for (int i = 0; i < length; i++) {
                 threads[i].start();
             }
+            for (int i = 0; i < length; i++) {
+                threads[i].waitForInit();
+            }
             return RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR);
         }
     }
@@ -173,46 +195,56 @@ public class FastRContext {
      * sublist contains the result of the evaluation with name "result". It may also have an
      * attribute "error" if the evaluation threw an exception, in which case the result will be NA.
      */
-    @RBuiltin(name = ".fastr.context.eval", kind = PRIMITIVE, parameterNames = {"exprs", "pc", "kind"}, behavior = COMPLEX)
-    public abstract static class Eval extends RBuiltinNode.Arg3 {
+    @RBuiltin(name = ".fastr.context.eval", kind = PRIMITIVE, parameterNames = {"exprs", "kind"}, behavior = COMPLEX)
+    public abstract static class Eval extends RBuiltinNode.Arg2 {
         @Override
         public Object[] getDefaultParameterValues() {
-            return new Object[]{RMissing.instance, 1, "SHARE_NOTHING"};
+            return new Object[]{RMissing.instance, FastROptions.SharedContexts.getBooleanValue() ? "SHARE_ALL" : "SHARE_NOTHING"};
         }
 
         static {
             Casts casts = new Casts(Eval.class);
             CastsHelper.exprs(casts);
-            CastsHelper.pc(casts);
             CastsHelper.kind(casts);
         }
 
         @Specialization
         @TruffleBoundary
-        protected Object eval(RAbstractStringVector exprs, int pc, String kind) {
+        protected Object eval(RAbstractStringVector exprs, String kind) {
             RContext.ContextKind contextKind = RContext.ContextKind.valueOf(kind);
+            if (FastROptions.SharedContexts.getBooleanValue() && contextKind != ContextKind.SHARE_ALL) {
+                throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, "Only shared contexts are allowed");
+            }
+            handleSharedContexts(contextKind);
 
-            Object[] results = new Object[pc];
-            if (pc == 1) {
+            int length = exprs.getLength();
+            Object[] results = new Object[length];
+            if (length == 1) {
                 ContextInfo info = createContextInfo(contextKind);
                 PolyglotEngine vm = info.createVM();
                 try {
-                    results[0] = RContext.EvalThread.run(vm, info, RSource.fromTextInternal(exprs.getDataAt(0), RSource.Internal.CONTEXT_EVAL));
+                    results[0] = RContext.EvalThread.run(vm, info, RSource.fromTextInternalInvisible(exprs.getDataAt(0), RSource.Internal.CONTEXT_EVAL));
                 } finally {
                     vm.dispose();
                 }
             } else {
                 // separate threads that run in parallel; invoking thread waits for completion
-                RContext.EvalThread[] threads = new RContext.EvalThread[pc];
-                for (int i = 0; i < pc; i++) {
+                RContext.EvalThread[] threads = new RContext.EvalThread[length];
+                for (int i = 0; i < length; i++) {
                     ContextInfo info = createContextInfo(contextKind);
-                    threads[i] = new RContext.EvalThread(info, RSource.fromTextInternal(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL));
+                    threads[i] = new RContext.EvalThread(info, RSource.fromTextInternalInvisible(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL));
+                }
+                if (contextKind == ContextKind.SHARE_ALL) {
+                    REnvironment.convertSearchpathToMultiSlot();
                 }
-                for (int i = 0; i < pc; i++) {
+                for (int i = 0; i < length; i++) {
                     threads[i].start();
                 }
+                for (int i = 0; i < length; i++) {
+                    threads[i].waitForInit();
+                }
                 try {
-                    for (int i = 0; i < pc; i++) {
+                    for (int i = 0; i < length; i++) {
                         threads[i].join();
                         results[i] = threads[i].getEvalResult();
                     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/parallel/R/forkcluster_overrides.R b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/parallel/R/forkcluster_overrides.R
index 42d5c9ce8b44849166eb70e73832f781475e471e..2d3ebf6b49a58ea052b43953b3c3e1c47aaaad39 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/parallel/R/forkcluster_overrides.R
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/parallel/R/forkcluster_overrides.R
@@ -11,22 +11,35 @@
 
 ## Derived from snow and parallel packages
 
-eval(expression(
+eval(expression({
+
+# overwritten functions:
+
+makeCluster <- function (spec, type = getClusterOption("type"), ...) {
+    switch(type,
+        PSOCK = makePSOCKcluster(spec, ...),
+        FORK = makeForkCluster(spec, ...),
+        SOCK = snow::makeSOCKcluster(spec, ...),
+        MPI = snow::makeMPIcluster(spec, ...),
+        NWS = snow::makeNWScluster(spec, ...),
+        SHARED = makeSHAREDcluster(spec, ...), # this line was added
+        stop("unknown cluster type"))
+}
+
+# added functions:
+
 closeNode.SHAREDnode <- function(node) {
     .fastr.channel.close(node$channel)
-}), asNamespace("parallel"))
+}
 
-eval(expression(
 sendData.SHAREDnode <- function(node, data) {
     .fastr.channel.send(node$channel, data)
-}), asNamespace("parallel"))
+}
 
-eval(expression(
 recvData.SHAREDnode <- function(node) {
     .fastr.channel.receive(node$channel)
-}), asNamespace("parallel"))
+}
 
-eval(expression(
 recvOneData.SHAREDcluster <- function(cl) {
 	channel_ids = lapply(cl, function(l) l[["channel"]])
     res <- .fastr.channel.select(channel_ids)
@@ -35,57 +48,67 @@ recvOneData.SHAREDcluster <- function(cl) {
 	indexes = lapply(cl, function(l, id) if (identical(l[["channel"]], id)) id else as.integer(NA), id=selected_id)
 	node_ind = which(as.double(indexes)==as.double(selected_id))
 	list(node = node_ind, value = res[[2]])
-}), asNamespace("parallel"))
-
-eval(expression(
-fastr.newSHAREDnode <- function(rank, options = defaultClusterOptions)
-{
-	# Add the "debug" option defaulted to FALSE, if the user didn't specify
-	# If the user gives TRUE, print extra stuff during cluster setup
-	debug <- FALSE
-	tryCatch(
-		debug <- parallel:::getClusterOption("debug", options),
-		error = function(e) { }
-	)
-	options <- parallel:::addClusterOptions(options, list(debug = debug))
+}
 
-	# generate unique values for channel keys (addition factor is chosen based on how snow generates port numbers)
-	port <- as.integer(parallel:::getClusterOption("port", options) + rank * 1000)
-	script <- file.path(R.home(), "com.oracle.truffle.r.native", "library", "parallel", "RSHAREDnode.R")
+newSHAREDnodes <- function(nnodes, debug, options = defaultClusterOptions) {
+	context_code <- vector("character", nnodes)
+	contexts <- vector("integer", nnodes)
+	channels <- vector("integer", nnodes)
+	outfile <- getClusterOption("outfile", options)
+	for (i in 1:nnodes) {
+		# generate unique values for channel keys (addition factor is chosen based on how snow generates port numbers)
+		port <- as.integer(parallel:::getClusterOption("port", options) + i * 1000)
+		
+		startup <- substitute(local({
+            makeSHAREDmaster <- function(key) {
+                channel <- .fastr.channel.get(as.integer(key))
+                structure(list(channel=channel), class = "SHAREDnode")
+            }
+            parallel:::sinkWorkerOutput(OUTFILE)
+            parallel:::slaveLoop(makeSHAREDmaster(PORT))
+        }), list(OUTFILE=outfile, PORT=port))
+		
+        context_code[[i]] <- paste0(deparse(startup), collapse="\n")
+        if (isTRUE(debug)) cat(sprintf("Starting context: %d with code %s\n", i, context_code[[i]]))
 
-    context_code <- paste0("commandArgs<-function() c('--args', 'PORT=", port, "'); source('", script, "')")
-	if (isTRUE(debug)) cat(sprintf("Starting context: %d with code %s\n", rank, context_code))
-
-    cx <- .fastr.context.spawn(context_code)
-
-	## Need to return a list here, in the same form as the
-	## "cluster" data structure.
-    channel <- .fastr.channel.create(port)
-	if (isTRUE(debug)) cat(sprintf("Context %d started!\n", rank))
-	structure(list(channel = channel, context=cx, rank = rank), class = "SHAREDnode")
-}), asNamespace("parallel"))
+		## Need to return a list here, in the same form as the
+		## "cluster" data structure.
+    	channels[[i]] <- .fastr.channel.create(port)
+		if (isTRUE(debug)) cat(sprintf("Context %d started!\n", i))
+	}
+    contexts <- .fastr.context.spawn(context_code)
+    cl <- vector("list", nnodes)
+	for (i in 1:nnodes) {
+		cl[[i]] <- structure(list(channel = channels[[i]], context=contexts[[i]], rank = i), class = "SHAREDnode")
+	}
+	cl
+}
 
-makeForkClusterExpr <- expression({
-makeForkCluster <- function(nnodes = getOption("mc.cores", 2L), options = defaultClusterOptions, ...)
-{
+makeSHAREDcluster <- function(nnodes = getOption("mc.cores", 2L), options = defaultClusterOptions, ...) {
     nnodes <- as.integer(nnodes)
     if(is.na(nnodes) || nnodes < 1L) stop("'nnodes' must be >= 1")
     .check_ncores(nnodes)
 	options <- addClusterOptions(options, list(...))
-    cl <- vector("list", nnodes)
-    for (i in seq_along(cl)) cl[[i]] <- fastr.newSHAREDnode(rank=i, options=options)
+
+	# Add the "debug" option defaulted to FALSE, if the user didn't specify
+	# If the user gives TRUE, print extra stuff during cluster setup
+	debug <- FALSE
+	if (exists("debug", envir=options, inherits=FALSE)) {
+		debug <- parallel:::getClusterOption("debug", options)
+	} else {
+		options <- parallel:::addClusterOptions(options, list(debug = debug))
+	}
+	
+    cl <- newSHAREDnodes(nnodes, debug = debug, options=options)
 	class(cl) <- c("SHAREDcluster", "cluster")
 	cl
-}; environment(makeForkCluster)<-asNamespace("parallel")})
-eval(makeForkClusterExpr, asNamespace("parallel"))
-# seems like we don't need these anymore, but let's make sure
-#eval(makeForkClusterExpr, as.environment("package:parallel"))
-
+}
 
-eval(expression(
 stopCluster.SHAREDcluster <- function(cl) {
     for (n in cl) {
         parallel:::postNode(n, "DONE")
         .fastr.context.join(n$context)
     }
+}
+
 }), asNamespace("parallel"))
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
index f9e15b0a6b16368280b78ca0151f666b4f24db0e..5df1356f04147c5cae76348b71b5d1212b09636f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
@@ -74,6 +74,7 @@ import com.oracle.truffle.r.runtime.env.frame.ActiveBinding;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.FrameAndSlotLookupResult;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.LookupResult;
+import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.MultiSlotData;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
@@ -570,8 +571,16 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
          */
         FrameSlot localSlot = variableFrame.getFrameDescriptor().findFrameSlot(identifier);
         // non-local reads can only be handled in a simple way if they are successful
-        if (localSlot != null && checkTypeSlowPath(frame, getValue(seenValueKinds, variableFrame, localSlot))) {
-            return new Match(localSlot);
+        if (localSlot != null) {
+            Object val = getValue(seenValueKinds, variableFrame, localSlot);
+            if (checkTypeSlowPath(frame, val)) {
+                if (val instanceof MultiSlotData) {
+                    RError.performanceWarning("polymorphic (slow path) lookup of symbol \"" + identifier + "\" from a multi slot");
+                    return new Polymorphic(variableFrame);
+                } else {
+                    return new Match(localSlot);
+                }
+            }
         }
 
         /*
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
index 13c607e358851a5b39313b9fc650e64b2d2aa620..2eb77334c9d86cdb3b18af0e955c8b07a448931b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
@@ -60,6 +60,11 @@ abstract class ReplacementNode extends OperatorNode {
         this.lhs = lhs;
     }
 
+    @Override
+    public final Node deepCopy() {
+        return RContext.getASTBuilder().process(this).asRNode();
+    }
+
     public static ReplacementNode create(SourceSection source, RSyntaxLookup operator, RNode target, RSyntaxElement lhs, RNode rhs, List<RSyntaxCall> calls,
                     String targetVarName, boolean isSuper, int tempNamesStartIndex, boolean isVoid) {
         CompilerAsserts.neverPartOfCompilation();
@@ -145,7 +150,7 @@ abstract class ReplacementNode extends OperatorNode {
             RSyntaxNode[] newArgs = new RSyntaxNode[2];
             newArgs[0] = (RSyntaxNode) oldArgs[0];
             newArgs[1] = builder.lookup(oldArgs[1].getLazySourceSection(), ((RSyntaxLookup) oldArgs[1]).getIdentifier() + "<-", true);
-            newSyntaxLHS = RCallSpecialNode.createCall(callLHS.getLazySourceSection(), ((RSyntaxNode) callLHS.getSyntaxLHS()).asRNode(), callLHS.getSyntaxSignature(), newArgs);
+            newSyntaxLHS = RCallSpecialNode.createCall(callLHS.getLazySourceSection(), builder.process(callLHS.getSyntaxLHS(), codeBuilderContext).asRNode(), callLHS.getSyntaxSignature(), newArgs);
         }
         return RCallSpecialNode.createCallInReplace(source, newSyntaxLHS.asRNode(), ArgumentsSignature.get(names), argNodes, 0, argNodes.length - 1).asRNode();
     }
@@ -346,7 +351,7 @@ abstract class ReplacementNode extends OperatorNode {
 
         GenericReplacementNode(SourceSection source, RSyntaxLookup operator, RNode target, RSyntaxElement lhs, RNode rhs, List<RSyntaxCall> calls, String targetVarName, boolean isSuper,
                         int tempNamesStartIndex) {
-            super(source, operator, lhs, rhs, tempNamesStartIndex);
+            super(source, operator, lhs, RContext.getASTBuilder().process(rhs.asRSyntaxNode()).asRNode(), tempNamesStartIndex);
             /*
              * When there are more than two function calls in LHS, then we save some function calls
              * by saving the intermediate results into temporary variables and reusing them.
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
index 89c214040ceda244a24290cb59deb3440901c544..2c87c80b612bb7698508071dfd5e94d0d103dc68 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
@@ -515,7 +515,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         }
         if (restartStackSlot == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            restartStackSlot = frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.RestartStack);
+            restartStackSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RFrameSlot.RestartStack, FrameSlotKind.Object);
         }
         return restartStackSlot;
     }
@@ -527,7 +527,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         }
         if (handlerStackSlot == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            handlerStackSlot = frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.HandlerStack);
+            handlerStackSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RFrameSlot.HandlerStack, FrameSlotKind.Object);
         }
         return handlerStackSlot;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
index f2407db5244cbdc42c9c845c5748c992d1e4b5a4..b635984a2cb511bea0b9716cacf2003f3c1470ea 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java
@@ -96,7 +96,7 @@ public class PromiseHelperNode extends RBaseNode {
             boolean deoptOne = false;
             for (FrameSlot slot : frame.getFrameDescriptor().getSlots().toArray(new FrameSlot[0])) {
                 // We're only interested in RPromises
-                if (slot.getKind() != FrameSlotKind.Object) {
+                if (slot.getKind() != FrameSlotKind.Object || !(slot.getIdentifier() instanceof String)) {
                     continue;
                 }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
index 5ba452ebe42f9b092bfb9e5b3439861e2691f379..e87a36945f15d09cdabd87d1c33cba3d6a790a3f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
@@ -24,7 +24,9 @@ package com.oracle.truffle.r.nodes.function;
 
 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.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.api.profiles.ConditionProfile;
@@ -165,7 +167,11 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
      */
     private RCallSpecialNode callSpecialParent;
 
-    private RCallSpecialNode(SourceSection sourceSection, RNode functionNode, RFunction expectedFunction, RSyntaxNode[] arguments, ArgumentsSignature signature, RNode special) {
+    private final boolean inReplace;
+    private final int[] ignoredArguments;
+
+    private RCallSpecialNode(SourceSection sourceSection, RNode functionNode, RFunction expectedFunction, RSyntaxNode[] arguments, ArgumentsSignature signature, RNode special, boolean inReplace,
+                    int[] ignoredArguments) {
         this.sourceSection = sourceSection;
         this.expectedFunction = expectedFunction;
         this.special = special;
@@ -173,6 +179,8 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         this.arguments = arguments;
         this.signature = signature;
         this.visible = expectedFunction.getRBuiltin().getVisibility();
+        this.inReplace = inReplace;
+        this.ignoredArguments = ignoredArguments;
     }
 
     /**
@@ -264,7 +272,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         RFunction expectedFunction = RContext.lookupBuiltin(name);
         RInternalError.guarantee(expectedFunction != null);
 
-        RCallSpecialNode callSpecial = new RCallSpecialNode(sourceSection, functionNode, expectedFunction, arguments, signature, special);
+        RCallSpecialNode callSpecial = new RCallSpecialNode(sourceSection, functionNode, expectedFunction, arguments, signature, special, inReplace, ignoredArguments);
         for (int i = 0; i < arguments.length; i++) {
             if (!inReplace || !contains(ignoredArguments, i)) {
                 if (arguments[i] instanceof RCallSpecialNode) {
@@ -316,6 +324,23 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         }
     }
 
+    @TruffleBoundary
+    private static void log(String format, Object... args) {
+        System.out.println(String.format(format, args));
+    }
+
+    @Override
+    public Node deepCopy() {
+        assert !inReplace && callSpecialParent == null && ignoredArguments.length == 0;
+        RCallSpecialNode node = (RCallSpecialNode) RContext.getASTBuilder().process(this).asRNode();
+        node.functionNode = node.insert(node.functionNode);
+        node.special = node.insert(node.special);
+        if (node.visibility != null) {
+            node.visibility = insert(node.visibility);
+        }
+        return node;
+    }
+
     private RCallNode getRCallNode(RSyntaxNode[] newArguments) {
         return RCallNode.createCall(sourceSection, functionNode, signature, newArguments);
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/GetVisibilityNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/GetVisibilityNode.java
index 61a735b9465ee9af14bdd25090a6f20dcb104ca7..b59180138a7b98913bb93d00fb60b0292b016802 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/GetVisibilityNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/GetVisibilityNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -32,6 +32,7 @@ import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.env.frame.RFrameSlot;
 
 /**
@@ -52,7 +53,7 @@ public final class GetVisibilityNode extends Node {
     public boolean execute(Frame frame) {
         if (frameSlot == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            frameSlot = frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.Visibility, FrameSlotKind.Boolean);
+            frameSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean);
         }
         try {
             return frame.getBoolean(frameSlot);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
index a259f498adbd9a3d08e22058bae9dd8d0ecf311c..f3fea2a553b20e487d2da962614b6c4b5738df9d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
@@ -37,6 +37,7 @@ import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RVisibility;
+import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.env.frame.RFrameSlot;
 
 /**
@@ -57,7 +58,7 @@ public final class SetVisibilityNode extends Node {
     private void ensureFrameSlot(Frame frame) {
         if (frameSlot == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            frameSlot = frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.Visibility, FrameSlotKind.Boolean);
+            frameSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean);
         }
     }
 
@@ -103,7 +104,7 @@ public final class SetVisibilityNode extends Node {
      */
     public static void executeAfterCallSlowPath(Frame frame, RCaller caller) {
         CompilerAsserts.neverPartOfCompilation();
-        frame.setBoolean(frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.Visibility, FrameSlotKind.Boolean), caller.getVisibility());
+        frame.setBoolean(FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean), caller.getVisibility());
     }
 
     /**
@@ -111,6 +112,6 @@ public final class SetVisibilityNode extends Node {
      */
     public static void executeSlowPath(Frame frame, boolean visibility) {
         CompilerAsserts.neverPartOfCompilation();
-        frame.setBoolean(frame.getFrameDescriptor().findOrAddFrameSlot(RFrameSlot.Visibility, FrameSlotKind.Boolean), visibility);
+        frame.setBoolean(FrameSlotChangeMonitor.findOrAddFrameSlot(frame.getFrameDescriptor(), RFrameSlot.Visibility, FrameSlotKind.Boolean), visibility);
     }
 }
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 688fd6c0e25ac23450fb9e1f2c0ff8e80b1be249..ad8d5d62991725bda18dea55e9e646a9abd96384 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
@@ -54,6 +54,8 @@ public enum FastROptions {
     UseInternalGridGraphics("Whether the internal (Java) grid graphics implementation should be used", true),
     UseSpecials("Whether the fast-path special call nodes should be created for simple enough arguments.", true),
     ForceSources("Generate source sections for unserialized code", false),
+    SharedContexts("Whether all child contexts are to be shared contexts", true),
+    SearchPathForcePromises("Whether all promises for frames on shared path are forced in presence of shared contexts", 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/RArguments.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java
index d5cd4a077fcaa35a49f9d1a42c911cfdd00e0ee7..1f41cbf04d1065e45362ffe5744d36e0c2a93e65 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java
@@ -293,12 +293,14 @@ public final class RArguments {
         frame.getArguments()[INDEX_IS_IRREGULAR] = isIrregularFrame;
     }
 
-    public static void setEnclosingFrame(Frame frame, MaterializedFrame newEnclosingFrame) {
+    public static void setEnclosingFrame(Frame frame, MaterializedFrame newEnclosingFrame, boolean updateDescriptors) {
         CompilerAsserts.neverPartOfCompilation();
         Object[] arguments = frame.getArguments();
         MaterializedFrame oldEnclosingFrame = (MaterializedFrame) arguments[INDEX_ENCLOSING_FRAME];
         arguments[INDEX_ENCLOSING_FRAME] = newEnclosingFrame;
-        FrameSlotChangeMonitor.setEnclosingFrame(frame, newEnclosingFrame, oldEnclosingFrame);
+        if (updateDescriptors) {
+            FrameSlotChangeMonitor.setEnclosingFrame(frame, newEnclosingFrame, oldEnclosingFrame);
+        }
     }
 
     public static void initializeEnclosingFrame(Frame frame, MaterializedFrame newEnclosingFrame) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
index 595a9c69e2ecea41e936c904830f9792b6251517..bc1cb211f156e4c0a9e698fd1cf9b945af97b894 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
@@ -28,8 +28,10 @@ import java.util.concurrent.Semaphore;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.RootCallTarget;
+import com.oracle.truffle.api.frame.FrameDescriptor;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.conn.RConnection;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
@@ -242,11 +244,15 @@ public class RChannel {
             // parent can be SerializedEnv or byte[]
             private final Object parent;
             private final DynamicObject attributes;
+            private final String name;
+            private final FrameDescriptor desc;
 
-            SerializedEnv(Bindings bindings, Object parent, DynamicObject attributes) {
+            SerializedEnv(Bindings bindings, Object parent, DynamicObject attributes, String name, FrameDescriptor desc) {
                 this.bindings = bindings;
                 this.parent = parent;
                 this.attributes = attributes;
+                this.name = name;
+                this.desc = desc;
             }
 
             public String[] getNames() {
@@ -264,6 +270,14 @@ public class RChannel {
             public DynamicObject getAttributes() {
                 return attributes;
             }
+
+            public String getName() {
+                return name;
+            }
+
+            public FrameDescriptor getDesc() {
+                return desc;
+            }
         }
 
         protected static class SerializedPromise {
@@ -294,12 +308,18 @@ public class RChannel {
         protected static class SerializedFunction {
             private final DynamicObject attributes;
             private final Object env;
-            private final RFunction serializedDef;
+            private final String name;
+            private final String packageName;
+            private final RBuiltinDescriptor builtinDesc;
+            private final RootCallTarget callTarget;
 
-            public SerializedFunction(DynamicObject attributes, Object env, RFunction serializedDef) {
+            public SerializedFunction(DynamicObject attributes, Object env, String name, String packageName, RBuiltinDescriptor builtinDesc, RootCallTarget callTarget) {
                 this.attributes = attributes;
                 this.env = env;
-                this.serializedDef = serializedDef;
+                this.name = name;
+                this.packageName = packageName;
+                this.builtinDesc = builtinDesc;
+                this.callTarget = callTarget;
             }
 
             public DynamicObject getAttributes() {
@@ -310,8 +330,20 @@ public class RChannel {
                 return env;
             }
 
-            public RFunction getSerializedDef() {
-                return serializedDef;
+            public String getName() {
+                return name;
+            }
+
+            public RBuiltinDescriptor getRBuiltin() {
+                return builtinDesc;
+            }
+
+            public RootCallTarget getTarget() {
+                return callTarget;
+            }
+
+            public String getPackageName() {
+                return packageName;
             }
         }
 
@@ -394,6 +426,7 @@ public class RChannel {
             }
         }
 
+        @TruffleBoundary
         private Object convertPrivateEnv(Object msg) throws IOException {
             int refInd = getRefIndex(msg);
             if (refInd != -1) {
@@ -408,7 +441,7 @@ public class RChannel {
             }
             SerializedEnv.Bindings bindings = createShareable(env);
 
-            return new SerializedEnv(bindings, convertPrivateSlow(env.getParent()), attributes);
+            return new SerializedEnv(bindings, convertPrivateSlow(env.getParent()), attributes, env.getName(), env.getFrame().getFrameDescriptor());
         }
 
         private SerializedPromise convertPrivatePromise(Object msg) throws IOException {
@@ -425,7 +458,7 @@ public class RChannel {
             RFunction fn = (RFunction) msg;
             Object env = convertPrivate(REnvironment.frameToEnvironment(fn.getEnclosingFrame()));
             DynamicObject attributes = fn.getAttributes();
-            return new SerializedFunction(attributes == null ? null : createShareableSlow(attributes, true), env, fn);
+            return new SerializedFunction(attributes == null ? null : createShareableSlow(attributes, true), env, fn.getName(), fn.getPackageName(), fn.getRBuiltin(), fn.getTarget());
         }
 
         private Object convertPrivateAttributable(Object msg) throws IOException {
@@ -603,7 +636,7 @@ public class RChannel {
             Object[] values = e.getValues();
             String[] names = e.getNames();
             assert values.length == names.length;
-            REnvironment.NewEnv env = RDataFactory.createNewEnv(null);
+            REnvironment.NewEnv env = RDataFactory.createNewEnv(e.getDesc(), e.getName());
             addReadRef(env);
             int ind = 0;
             for (String n : names) {
@@ -611,7 +644,7 @@ public class RChannel {
                 env.safePut(n, newValue);
             }
             REnvironment parent = (REnvironment) unserializeObject(e.getParent());
-            RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame());
+            RArguments.setEnclosingFrame(env.getFrame(), parent.getFrame(), false);
             DynamicObject attributes = e.getAttributes();
             if (attributes != null) {
                 env.initAttributes(attributes);
@@ -636,13 +669,17 @@ public class RChannel {
 
         @TruffleBoundary
         private RFunction unserializeFunction(SerializedFunction f) throws IOException {
-            RFunction fun = f.getSerializedDef();
             REnvironment env = (REnvironment) unserializeObject(f.getEnv());
             MaterializedFrame enclosingFrame = env.getFrame();
-            HasSignature root = (HasSignature) fun.getTarget().getRootNode();
-            RootCallTarget target = root.duplicateWithNewFrameDescriptor();
-            FrameSlotChangeMonitor.initializeEnclosingFrame(target.getRootNode().getFrameDescriptor(), enclosingFrame);
-            RFunction fn = RDataFactory.createFunction(fun.getName(), fun.getPackageName(), target, null, enclosingFrame);
+            RFunction fn;
+            if (FastROptions.SharedContexts.getBooleanValue()) {
+                fn = RDataFactory.createFunction(f.getName(), f.getPackageName(), f.getTarget(), f.getRBuiltin(), enclosingFrame);
+            } else {
+                HasSignature root = (HasSignature) f.getTarget().getRootNode();
+                RootCallTarget target = root.duplicateWithNewFrameDescriptor();
+                FrameSlotChangeMonitor.initializeEnclosingFrame(target.getRootNode().getFrameDescriptor(), enclosingFrame);
+                fn = RDataFactory.createFunction(f.getName(), f.getPackageName(), target, null, enclosingFrame);
+            }
             DynamicObject attributes = f.getAttributes();
             if (attributes != null) {
                 assert fn.getAttributes() == null;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index f1086ac6da4bef8bc6af79815e8ea6a5b6e346a7..bfa0177952d504c0fac8610c4a53f56d1bb03489 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -264,7 +264,13 @@ public final class RError extends RuntimeException {
     @TruffleBoundary
     public static void performanceWarning(String string) {
         if (FastROptions.PerformanceWarnings.getBooleanValue()) {
-            warning(RError.SHOW_CALLER2, Message.PERFORMANCE, string);
+            System.out.println("Performance warning: " + string);
+            StackTraceElement[] trace = new RuntimeException().getStackTrace();
+            for (int i = 1; i < trace.length && i < 8; i++) {
+                StackTraceElement element = trace[i];
+                System.out.println("  at " + element.getClassName() + "." + element.getMethodName() + "(" + element.getFileName() + ":" + element.getLineNumber() + ")");
+            }
+            // warning(RError.SHOW_CALLER2, Message.PERFORMANCE, string);
         }
     }
 
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 412cd0b07ee1e7648e6317511761a916755deab7..6a5b182e76243b8c5d1ea97ee819b20d8cf85b68 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
@@ -597,7 +597,10 @@ public class RErrorHandling {
          */
         ContextStateImpl errorHandlingState = getRErrorHandlingState();
         RFunction f = errorHandlingState.getDotSignalSimpleWarning();
-        RContext.getRRuntimeASTAccess().callback(f, new Object[]{warningMessage, call});
+        if (f != null) {
+            RContext.getRRuntimeASTAccess().callback(f, new Object[]{warningMessage, call});
+        }
+        // otherwise the subsystem is not initialized yet - no warning
     }
 
     private static void warningcallDfltWithCall(Object call, Message msg, Object... args) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
index 8104d4e5a0a9d9404b9440f1e026900ed2e3d35f..0f5b22a965c0365c8c3b3747b4f1db2ea7354388 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java
@@ -193,6 +193,13 @@ public class RRuntime {
         }
     }
 
+    /**
+     * Create a {@link MaterializedFrame} for functions shared between different contexts.
+     */
+    public static MaterializedFrame createNewFrame(FrameDescriptor frameDescriptor) {
+        return Truffle.getRuntime().createMaterializedFrame(RArguments.createUnitialized(), frameDescriptor);
+    }
+
     /**
      * Create an {@link VirtualFrame} for a non-function environment, e.g., a package frame or the
      * global environment.
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
index 5f6462db6d8b31943883d61dea6676c84a973d53..41ea6dacdaef4fa6b2282d0bc842ecc33a2f4a50 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
@@ -107,6 +107,13 @@ public class RSource {
         return fromTextInternal(text, description, RRuntime.R_APP_MIME);
     }
 
+    /**
+     * Create an {@code internal} source from {@code text} and {@code description}.
+     */
+    public static Source fromTextInternalInvisible(String text, Internal description) {
+        return fromTextInternalInvisible(text, description, RRuntime.R_APP_MIME);
+    }
+
     /**
      * Create an {@code internal} source from {@code text} and {@code description} of given
      * {@code mimeType}.
@@ -116,6 +123,15 @@ public class RSource {
         return Source.newBuilder(text).name(description.string).mimeType(mimeType).internal().interactive().build();
     }
 
+    /**
+     * Create an {@code internal} source from {@code text} and {@code description} of given
+     * {@code mimeType}.
+     */
+
+    public static Source fromTextInternalInvisible(String text, Internal description, String mimeType) {
+        return Source.newBuilder(text).name(description.string).mimeType(mimeType).internal().build();
+    }
+
     /**
      * Create an {@code internal} source for a deparsed package from {@code text} and
      * {@code packageName}.
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
index d533301e924c73398f388816cdb280eda7b6e5ce..a5ac484ad14ccb207471af5f54f7a248e96fd720 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java
@@ -60,6 +60,7 @@ import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.MultiSlotData;
 import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
@@ -362,6 +363,7 @@ public final class Utils {
      */
     @TruffleBoundary
     public static Frame getStackFrame(FrameAccess fa, RCaller target) {
+        RError.performanceWarning("slow frame access - getStackFrame1");
         assert target != null;
         return Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<Frame>() {
             boolean first = true;
@@ -388,6 +390,7 @@ public final class Utils {
      */
     @TruffleBoundary
     public static Frame getStackFrame(FrameAccess fa, int depth) {
+        RError.performanceWarning("slow frame access - getStackFrame2");
         return Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<Frame>() {
             boolean first = true;
 
@@ -418,6 +421,7 @@ public final class Utils {
      */
     @TruffleBoundary
     public static <T> T iterateRFrames(FrameAccess fa, Function<Frame, T> func) {
+        RError.performanceWarning("slow frame access - iterateRFrames");
         return Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<T>() {
             boolean first = true;
 
@@ -463,6 +467,7 @@ public final class Utils {
      */
     @TruffleBoundary
     public static Frame getActualCurrentFrame() {
+        RError.performanceWarning("slow frame access - getActualCurrentFrame");
         FrameInstance frameInstance = Truffle.getRuntime().getCurrentFrame();
         if (frameInstance == null) {
             // Might be the case during initialization, when envs are prepared before the actual
@@ -528,6 +533,7 @@ public final class Utils {
      */
     @TruffleBoundary
     public static Object createTraceback(int skip) {
+        RError.performanceWarning("slow frame access - createTraceback");
         FrameInstance current = Truffle.getRuntime().getCurrentFrame();
         if (current != null) {
             TracebackVisitor fiv = new TracebackVisitor(skip);
@@ -543,6 +549,7 @@ public final class Utils {
      */
     @TruffleBoundary
     public static String createStackTrace(boolean printFrameSlots) {
+        RError.performanceWarning("slow frame access - createStackTrace");
         FrameInstance current = Truffle.getRuntime().getCurrentFrame();
         if (current == null) {
             return "no R stack trace available\n";
@@ -594,12 +601,9 @@ public final class Utils {
                     FrameDescriptor frameDescriptor = unwrapped.getFrameDescriptor();
                     for (FrameSlot s : frameDescriptor.getSlots()) {
                         str.append("\n      ").append(s.getIdentifier()).append(" = ");
-                        Object value;
-                        try {
-                            value = unwrapped.getValue(s);
-                        } catch (Throwable t) {
-                            str.append("<exception ").append(t.getClass().getSimpleName()).append(" while acquiring slot ").append(s.getIdentifier()).append(">");
-                            continue;
+                        Object value = unwrapped.getValue(s);
+                        if (value instanceof MultiSlotData) {
+                            value = ((MultiSlotData) value).get(RContext.getInstance().getMultiSlotInd());
                         }
                         try {
                             if (value instanceof RAbstractContainer && ((RAbstractContainer) value).getLength() > 32) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
index c1d39f9b1e21dc4bb76377f176aa8afb31bb60a6..04862083a6b5bc24b883ad9f05cc01b70734ae92 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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.util.concurrent.atomic.AtomicInteger;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RStartParams;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 
@@ -41,6 +42,7 @@ public final class ContextInfo {
     static final String CONFIG_KEY = "fastrContextInfo";
 
     private static final AtomicInteger contextInfoIds = new AtomicInteger();
+    private static final AtomicInteger multiSlotInds = new AtomicInteger(-1);
 
     private final RStartParams startParams;
     private final String[] env;
@@ -54,18 +56,32 @@ public final class ContextInfo {
     private final RContext parent;
     private final ConsoleHandler consoleHandler;
     private final int id;
+    private final int multiSlotInd;
     private PolyglotEngine vm;
 
-    private ContextInfo(RStartParams startParams, String[] env, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone, int id) {
+    private ContextInfo(RStartParams startParams, String[] env, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone, int id, int multiSlotInd) {
         this.startParams = startParams;
         this.env = env;
         this.kind = kind;
         this.parent = parent;
         this.consoleHandler = consoleHandler;
         this.systemTimeZone = systemTimeZone;
+        this.multiSlotInd = multiSlotInd;
         this.id = id;
     }
 
+    /**
+     * Correctness of this method relies on the fact that parallel contexts are started only after
+     * all of them (and their info) is created (in FastRContext).
+     */
+    public static int contextNum() {
+        return multiSlotInds.get() + 1;
+    }
+
+    public static void resetMultiSlotIndexGenerator() {
+        multiSlotInds.set(0); // to account for primordial context
+    }
+
     public PolyglotEngine createVM() {
         PolyglotEngine newVM = PolyglotEngine.newBuilder().config("application/x-r", CONFIG_KEY, this).build();
         this.vm = newVM;
@@ -91,7 +107,17 @@ public final class ContextInfo {
      */
     public static ContextInfo create(RStartParams startParams, String[] env, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone) {
         int id = contextInfoIds.incrementAndGet();
-        return new ContextInfo(startParams, env, kind, parent, consoleHandler, systemTimeZone, id);
+        int multiSlotInd = multiSlotInds.get();
+        if (kind == ContextKind.SHARE_ALL || kind == ContextKind.SHARE_NOTHING) {
+            multiSlotInd = multiSlotInds.incrementAndGet();
+        }
+        // no increment for SHARE_PARENT_RW as it accesses the same data as its parent whose
+        // execution is suspended
+        if (kind == ContextKind.SHARE_PARENT_RO) {
+            throw RInternalError.shouldNotReachHere();
+        }
+        assert kind != ContextKind.SHARE_PARENT_RW || (kind == ContextKind.SHARE_PARENT_RW && parent.getKind() == ContextKind.SHARE_NOTHING && parent.getMultiSlotInd() == 0);
+        return new ContextInfo(startParams, env, kind, parent, consoleHandler, systemTimeZone, id, kind == ContextKind.SHARE_PARENT_RW ? 0 : multiSlotInd);
     }
 
     public static ContextInfo create(RStartParams startParams, String[] env, ContextKind kind, RContext parent, ConsoleHandler consoleHandler) {
@@ -141,6 +167,10 @@ public final class ContextInfo {
         return id;
     }
 
+    public int getMultiSlotInd() {
+        return multiSlotInd;
+    }
+
     public PolyglotEngine getVM() {
         return vm;
     }
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 64339a2fc5dac568b8b2845d39e1f517da5c5210..b4a193b8fa0aa2726c82474ad2f867bbcd0ee0f3 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.TimeZone;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
 
 import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -134,7 +135,12 @@ public final class RContext extends ExecutionContext {
          * shallow copy of the environments associated with the default packages of the parent
          * context at the time the context is created.
          */
-        SHARE_PARENT_RO;
+        SHARE_PARENT_RO,
+
+        /**
+         * Shares all environments on the search path.
+         */
+        SHARE_ALL;
 
         public static final ContextKind[] VALUES = values();
     }
@@ -217,6 +223,7 @@ public final class RContext extends ExecutionContext {
         private final Source source;
         private final ContextInfo info;
         private RList evalResult;
+        private Semaphore init = new Semaphore(0);
 
         public static final Map<Integer, Thread> threads = new ConcurrentHashMap<>();
 
@@ -235,6 +242,7 @@ public final class RContext extends ExecutionContext {
             } catch (Throwable t) {
                 throw new RInternalError(t, "error while initializing eval thread");
             }
+            init.release();
             try {
                 evalResult = run(vm, info, source);
             } finally {
@@ -243,6 +251,19 @@ public final class RContext extends ExecutionContext {
             }
         }
 
+        /*
+         * Parent context uses this method to wait for initialization of the child to complete to
+         * prevent potential updates to runtime's meta data from interfering with program's
+         * execution.
+         */
+        public void waitForInit() {
+            try {
+                init.acquire();
+            } catch (InterruptedException x) {
+                throw new RInternalError(x, "error waiting to initialize eval thread");
+            }
+        }
+
         /**
          * Convenience method for {@code .fastr.context.eval} in same thread.
          */
@@ -387,6 +408,10 @@ public final class RContext extends ExecutionContext {
     private static final Assumption singleContextAssumption = Truffle.getRuntime().createAssumption("single RContext");
     @CompilationFinal private static RContext singleContext;
 
+    // need an additional flag as we don't want multi-slot processing to start until context
+    // initialization is fully complete - singleContext flag is not good enough for that
+    private static final Assumption isSingleContextAssumption = Truffle.getRuntime().createAssumption("is single RContext");
+
     private final Env env;
     private final HashMap<String, TruffleObject> exportedSymbols = new HashMap<>();
     private final boolean initial;
@@ -465,7 +490,7 @@ public final class RContext extends ExecutionContext {
         this.stateROptions = ROptions.ContextStateImpl.newContextState(stateREnvVars);
         this.stateRProfile = RProfile.newContextState(stateREnvVars);
         this.stateStdConnections = StdConnections.ContextStateImpl.newContextState();
-        this.stateREnvironment = REnvironment.ContextStateImpl.newContextState();
+        this.stateREnvironment = REnvironment.ContextStateImpl.newContextState(this);
         this.stateRErrorHandling = RErrorHandling.ContextStateImpl.newContextState();
         this.stateRConnection = ConnectionSupport.ContextStateImpl.newContextState();
         this.stateRNG = RRNG.ContextStateImpl.newContextState();
@@ -636,6 +661,14 @@ public final class RContext extends ExecutionContext {
         return info.getKind();
     }
 
+    public int getId() {
+        return info.getId();
+    }
+
+    public int getMultiSlotInd() {
+        return info.getMultiSlotInd();
+    }
+
     @TruffleBoundary
     public static RContext getThreadLocalInstance() {
         return threadLocalContext.get();
@@ -654,6 +687,14 @@ public final class RContext extends ExecutionContext {
         return result;
     }
 
+    public static boolean isSingle() {
+        return isSingleContextAssumption.isValid();
+    }
+
+    public static void markNonSingle() {
+        isSingleContextAssumption.invalidate();
+    }
+
     public static RContext getInstance() {
         RContext context = singleContext;
         if (singleContextAssumption.isValid() && context != null) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
index ee8b17a277e84e17a58aac2f08d58f69f0aa3ea3..2192e8f0598c9b472336e793a2cefe92a5593ef8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java
@@ -31,6 +31,7 @@ import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.RootCallTarget;
+import com.oracle.truffle.api.frame.FrameDescriptor;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.utilities.CyclicAssumption;
 import com.oracle.truffle.r.runtime.FastROptions;
@@ -499,6 +500,11 @@ public final class RDataFactory {
         return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<internal-env-" + environmentCount.incrementAndGet() + ">"), REnvironment.UNNAMED));
     }
 
+    @TruffleBoundary
+    public static REnvironment.NewEnv createNewEnv(FrameDescriptor desc, String name) {
+        return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNewFrame(desc), name));
+    }
+
     @TruffleBoundary
     public static REnvironment.NewEnv createNewEnv(String name) {
         return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<new-env-" + environmentCount.incrementAndGet() + ">"), name));
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 56100651dd85980d21657b88e045987d2e07fa41..b8ba2fe1c75518f24ba5f714d69ba7077ecbbd99 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
@@ -29,6 +29,7 @@ import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.Frame;
+import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.runtime.AnonymousFrameVariable;
@@ -41,6 +42,7 @@ import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.VirtualEvalFrame;
 import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -48,6 +50,7 @@ import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.env.frame.NSBaseMaterializedFrame;
 import com.oracle.truffle.r.runtime.env.frame.REnvEmptyFrameAccess;
 import com.oracle.truffle.r.runtime.env.frame.REnvFrameAccess;
@@ -152,8 +155,15 @@ public abstract class REnvironment extends RAttributeStorage {
             beforeDestroyContext(context, this);
         }
 
-        public static ContextStateImpl newContextState() {
-            return new ContextStateImpl(RRuntime.createNonFunctionFrame("global"));
+        public static ContextStateImpl newContextState(RContext context) {
+            MaterializedFrame newGlobalFrame;
+            if (context.getKind() == ContextKind.SHARE_ALL) {
+                ContextStateImpl parentState = context.getParent().stateREnvironment;
+                newGlobalFrame = parentState.getGlobalFrame();
+            } else {
+                newGlobalFrame = RRuntime.createNonFunctionFrame("global");
+            }
+            return new ContextStateImpl(newGlobalFrame);
         }
 
         public void initialize(Base newBaseEnv, REnvironment newNamespaceRegistry, SearchPath newSearchPath) {
@@ -329,6 +339,7 @@ public abstract class REnvironment extends RAttributeStorage {
                 /* We make shallow copies of all the default package environments in the parent */
                 ContextStateImpl parentState = context.getParent().stateREnvironment;
                 SearchPath parentSearchPath = parentState.getSearchPath();
+                assert parentSearchPath.size() > 1;
                 // clone all the environments below global from the parent
                 REnvironment e = parentSearchPath.get(1).cloneEnv(globalFrame);
                 // create the new Global with clone top as parent
@@ -352,6 +363,15 @@ public abstract class REnvironment extends RAttributeStorage {
                 break;
             }
 
+            case SHARE_ALL: {
+                ContextStateImpl parentState = context.getParent().stateREnvironment;
+                // TODO: may be worthwhile to assert for all environments on the search path there
+                // is 1:1 descriptor:frame mapping (as they are all meant to be shared in we rely on
+                // the single descriptor information to identify accesses to shared frames)
+                contextState.initialize(parentState.getBaseEnv(), parentState.getNamespaceRegistry(), parentState.getSearchPath());
+                break;
+            }
+
             case SHARE_NOTHING: {
                 // SHARE_NOTHING: baseInitialize takes care of everything
                 break;
@@ -747,7 +767,7 @@ public abstract class REnvironment extends RAttributeStorage {
      */
     public void setParent(REnvironment env) {
         if (getParent() != env) {
-            RArguments.setEnclosingFrame(getFrame(), env.getFrame());
+            RArguments.setEnclosingFrame(getFrame(), env.getFrame(), true);
         }
     }
 
@@ -890,6 +910,32 @@ public abstract class REnvironment extends RAttributeStorage {
         return getPrintName();
     }
 
+    public static void convertSearchpathToMultiSlot() {
+        CompilerAsserts.neverPartOfCompilation();
+        RContext.markNonSingle();
+        ContextStateImpl parentState = RContext.getInstance().stateREnvironment;
+        SearchPath searchPath = parentState.getSearchPath();
+        assert searchPath.size() > 0 && searchPath.get(0).getSearchName() == Global.SEARCHNAME;
+        // for global space don't replicate entries as all contexts should see their own values
+        FrameSlotChangeMonitor.handleAllMultiSlots(searchPath.get(0).getFrame(), false);
+        for (int i = 1; i < searchPath.size(); i++) {
+            FrameSlotChangeMonitor.handleAllMultiSlots(searchPath.get(i).getFrame(), true);
+        }
+        REnvironment namespaces = parentState.namespaceRegistry;
+        Frame namespacesFrame = namespaces.getFrame();
+        // make a copy avoid potential updates to the array iterated over
+        FrameSlot[] slots = new FrameSlot[namespacesFrame.getFrameDescriptor().getSlots().size()];
+        slots = namespacesFrame.getFrameDescriptor().getSlots().toArray(slots);
+        for (int i = 0; i < slots.length; i++) {
+            REnvironment namespaceEnv = (REnvironment) namespacesFrame.getValue(slots[i]);
+            if (namespaceEnv != Base.baseNamespaceEnv()) {
+                // base namespace frame redirects all accesses to base frame and this would
+                // result in processing the slots twice
+                FrameSlotChangeMonitor.handleAllMultiSlots(namespaceEnv.getFrame(), true);
+            }
+        }
+    }
+
     private static final class BaseNamespace extends REnvironment {
         private BaseNamespace(String name, MaterializedFrame frame) {
             super(name, frame);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
index 323f4d154d2e181b0be9d8d36bd597d5e602221e..cdb9f13b1c530c131cd8606ea5a29f683be5b4d2 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/FrameSlotChangeMonitor.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.Assumption;
 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.Truffle;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.FrameDescriptor;
@@ -44,9 +45,12 @@ import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.nodes.InvalidAssumptionException;
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.StableValue;
+import com.oracle.truffle.r.runtime.context.ContextInfo;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RPromise;
 
 /**
@@ -147,7 +151,7 @@ public final class FrameSlotChangeMonitor {
         public Object getValue() {
             // fast path execution should use getFrame / getSlot
             CompilerAsserts.neverPartOfCompilation("FrameAndSlotLookupResult.getValue() should not be used in fast path execution");
-            return frame.getValue(slot);
+            return FrameSlotChangeMonitor.getValue(slot, frame);
         }
 
         public MaterializedFrame getFrame() throws InvalidAssumptionException {
@@ -242,6 +246,7 @@ public final class FrameSlotChangeMonitor {
                 } else {
                     FrameDescriptorMetaData currentMetaData = getMetaData(current);
                     if (currentMetaData.singletonFrame == null) {
+                        // no stable value and no singleton frame
                         return null;
                     } else {
                         assert currentMetaData.singletonFrame.get() != null;
@@ -312,7 +317,8 @@ public final class FrameSlotChangeMonitor {
         return frame == null ? null : frame instanceof NSBaseMaterializedFrame ? ((NSBaseMaterializedFrame) frame).getMarkerFrameDescriptor() : frame.getFrameDescriptor();
     }
 
-    private static FrameDescriptorMetaData getMetaData(FrameDescriptor descriptor) {
+    private static synchronized FrameDescriptorMetaData getMetaData(FrameDescriptor descriptor) {
+        CompilerAsserts.neverPartOfCompilation();
         FrameDescriptorMetaData result = frameDescriptors.get(descriptor);
         assert result != null : "null metadata for " + descriptor;
         return result;
@@ -452,6 +458,24 @@ public final class FrameSlotChangeMonitor {
         // System.out.println(String.format(format, args));
     }
 
+    public static final class MultiSlotData {
+
+        private final Object[] data = new Object[ContextInfo.contextNum()];
+
+        public Object get(int ind) {
+            return data[ind];
+        }
+
+        public void set(int ind, Object val) {
+            data[ind] = val;
+        }
+
+        public void setAll(Object val) {
+            Arrays.fill(data, val);
+        }
+
+    }
+
     private static final class FrameSlotInfoImpl {
         /**
          * This is meant to monitor updates performed on {@link FrameSlot}. Each {@link FrameSlot}
@@ -464,11 +488,14 @@ public final class FrameSlotChangeMonitor {
          * comes into play.<br/>
          */
         private final Assumption nonLocalModifiedAssumption = Truffle.getRuntime().createAssumption();
+        private final Assumption noMultiSlot = Truffle.getRuntime().createAssumption();
 
-        @CompilationFinal private StableValue<Object> stableValue;
+        @CompilationFinal private volatile StableValue<Object> stableValue;
         private int invalidationCount;
+        private final boolean possibleMultiSlot;
 
-        FrameSlotInfoImpl(boolean isSingletonFrame, boolean isGlobalEnv, Object identifier) {
+        FrameSlotInfoImpl(boolean isSingletonFrame, boolean isGlobalEnv, Object identifier, boolean isNewEnv) {
+            this.possibleMultiSlot = isSingletonFrame && !isNewEnv;
             if (isSingletonFrame) {
                 stableValue = new StableValue<>(null, identifier.toString());
                 invalidationCount = isGlobalEnv ? MAX_GLOBAL_ENV_INVALIDATION_COUNT : MAX_INVALIDATION_COUNT;
@@ -481,29 +508,39 @@ public final class FrameSlotChangeMonitor {
             return stableValue != null;
         }
 
+        public boolean possibleMultiSlot() {
+            return possibleMultiSlot;
+        }
+
         /*
          * Special cases for primitive types to force value (instead of identity) comparison.
          */
 
-        public void setValue(byte value, FrameSlot slot) {
+        private void setValue(boolean value, FrameSlot slot) {
+            if (stableValue != null && (!(stableValue.getValue() instanceof Boolean) || ((boolean) stableValue.getValue()) != value)) {
+                invalidateStableValue(value, slot);
+            }
+        }
+
+        private void setValue(byte value, FrameSlot slot) {
             if (stableValue != null && (!(stableValue.getValue() instanceof Byte) || ((byte) stableValue.getValue()) != value)) {
                 invalidateStableValue(value, slot);
             }
         }
 
-        public void setValue(int value, FrameSlot slot) {
+        private void setValue(int value, FrameSlot slot) {
             if (stableValue != null && (!(stableValue.getValue() instanceof Integer) || ((int) stableValue.getValue()) != value)) {
                 invalidateStableValue(value, slot);
             }
         }
 
-        public void setValue(double value, FrameSlot slot) {
+        private void setValue(double value, FrameSlot slot) {
             if (stableValue != null && (!(stableValue.getValue() instanceof Double) || ((double) stableValue.getValue()) != value)) {
                 invalidateStableValue(value, slot);
             }
         }
 
-        public void setValue(Object value, FrameSlot slot) {
+        private void setValue(Object value, FrameSlot slot) {
             if (stableValue != null && stableValue.getValue() != value) {
                 invalidateStableValue(value, slot);
             }
@@ -525,6 +562,110 @@ public final class FrameSlotChangeMonitor {
         public StableValue<Object> getStableValue() {
             return stableValue;
         }
+
+        private static void setNewMultiValue(Frame frame, FrameSlot slot, MultiSlotData data, Object newValue) {
+            int ind = RContext.getInstance().getMultiSlotInd();
+            data.set(ind, newValue);
+            frame.setObject(slot, data);
+        }
+
+        private static boolean evalAndSetPromise(Frame frame, FrameSlot slot, FrameSlotInfoImpl info) {
+            Object prevValue = info.stableValue.getValue();
+            if (prevValue instanceof RPromise) {
+                prevValue = RContext.getRRuntimeASTAccess().forcePromise("searchPathPromiseForce", prevValue);
+                if (prevValue instanceof Boolean) {
+                    frame.setBoolean(slot, (boolean) prevValue);
+                    info.setValue((boolean) prevValue, slot);
+                } else if (prevValue instanceof Byte) {
+                    frame.setByte(slot, (byte) prevValue);
+                    info.setValue((byte) prevValue, slot);
+                } else if (prevValue instanceof Integer) {
+                    frame.setInt(slot, (int) prevValue);
+                    info.setValue((int) prevValue, slot);
+                } else if (prevValue instanceof Double) {
+                    frame.setDouble(slot, (double) prevValue);
+                    info.setValue((double) prevValue, slot);
+                } else {
+                    frame.setObject(slot, prevValue);
+                    info.setValue(prevValue, slot);
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        public static void handleSearchPathMultiSlot(Frame frame, FrameSlot slot, boolean replicate) {
+            CompilerAsserts.neverPartOfCompilation();
+            while (true) {
+                FrameSlotInfoImpl info = (FrameSlotInfoImpl) slot.getInfo();
+                if (info.stableValue == null || !replicate) {
+                    // create a multi slot for slots whose stableValue is null but also for all
+                    // slots of
+                    // the global frame (which are marked as !replicate)
+                    info.stableValue = null;
+                    info.nonLocalModifiedAssumption.invalidate();
+                    info.noMultiSlot.invalidate();
+                    info.invalidationCount = 0;
+                    MultiSlotData data = new MultiSlotData();
+                    Object prevValue = frame.getValue(slot);
+                    // TODO: do we have to worry that prevValue can be invalid?
+                    if (prevValue instanceof MultiSlotData) {
+                        // this handles the case when we create share contexts for the second time -
+                        // existing multi slots are an artifact of the previous executions and must
+                        // be
+                        // discarded
+                        // TOOD: consider re-using multi slots but since we don't expect many of
+                        // them,
+                        // perhaps it's too much work for too little gain
+                        prevValue = ((MultiSlotData) prevValue).get(0);
+                    } else if (FastROptions.SearchPathForcePromises.getBooleanValue()) {
+                        prevValue = RContext.getRRuntimeASTAccess().forcePromise("searchPathPromiseForce", prevValue);
+                    }
+                    if (replicate) {
+                        data.setAll(prevValue);
+                    } else {
+                        data.set(0, prevValue);
+                    }
+                    frame.setObject(slot, data);
+                    break;
+                } else {
+                    if (!FastROptions.SearchPathForcePromises.getBooleanValue() || !evalAndSetPromise(frame, slot, info)) {
+                        break;
+                    }
+                    // otherwise stable value may get nullified and slot turned into multi slot
+                }
+
+            }
+        }
+
+        @TruffleBoundary
+        public synchronized void setMultiSlot(Frame frame, FrameSlot slot, Object newValue) {
+            // TODO: perhaps putting the whole thing behind the Truffle boundary an overkill, but on
+            // the other hand it shouldn't happen often and not on the fast path
+            MultiSlotData data;
+            if (stableValue == null) {
+                // already a multi slot - should be visible to all threads
+                data = (MultiSlotData) frame.getValue(slot);
+                int ind = RContext.getInstance().getMultiSlotInd();
+                data.set(ind, newValue);
+            } else {
+                nonLocalModifiedAssumption.invalidate();
+                invalidationCount = 0;
+                // TODO: is it necessary since we nullify stable value?
+                stableValue.getAssumption().invalidate();
+                noMultiSlot.invalidate();
+                data = new MultiSlotData();
+                Object prevValue = frame.getValue(slot);
+                // value was stable so this slot is set by primordial context
+                data.set(0, prevValue);
+                setNewMultiValue(frame, slot, data, newValue);
+                // this should create happens-before with stable value reads during lookup, thus
+                // making preceding update to the actual frame OK to read without additional
+                // synchronization
+                stableValue = null;
+            }
+        }
     }
 
     /**
@@ -540,22 +681,32 @@ public final class FrameSlotChangeMonitor {
         Object info = slot.getInfo();
         if (!(info instanceof FrameSlotInfoImpl)) {
             CompilerDirectives.transferToInterpreter();
-            throw RInternalError.shouldNotReachHere("Each FrameSlot should hold a FrameSlotInfo in its info field!");
+            throw RInternalError.shouldNotReachHere("Each FrameSlot should hold a FrameSlotInfo in its info field! " + slot.getIdentifier().getClass() + " " + slot.getIdentifier());
         }
         return (FrameSlotInfoImpl) info;
     }
 
     // methods for creating new frame slots
 
-    public static synchronized FrameSlot findOrAddFrameSlot(FrameDescriptor fd, Object identifier, FrameSlotKind initialKind) {
+    public static FrameSlot findOrAddFrameSlot(FrameDescriptor fd, String identifier, FrameSlotKind initialKind) {
+        return findOrAddFrameSlot(fd, (Object) identifier, initialKind);
+    }
+
+    public static FrameSlot findOrAddFrameSlot(FrameDescriptor fd, RFrameSlot identifier, FrameSlotKind initialKind) {
+        return findOrAddFrameSlot(fd, (Object) identifier, initialKind);
+    }
+
+    private static synchronized FrameSlot findOrAddFrameSlot(FrameDescriptor fd, Object identifier, FrameSlotKind initialKind) {
         CompilerAsserts.neverPartOfCompilation();
+        assert identifier instanceof String || identifier instanceof RFrameSlot;
         FrameSlot frameSlot = fd.findFrameSlot(identifier);
         if (frameSlot != null) {
             return frameSlot;
         } else {
             FrameDescriptorMetaData metaData = getMetaData(fd);
             invalidateNames(metaData, Arrays.asList(identifier));
-            return fd.addFrameSlot(identifier, new FrameSlotInfoImpl(metaData.singletonFrame != null, "global".equals(metaData.name), identifier), initialKind);
+            return fd.addFrameSlot(identifier, new FrameSlotInfoImpl(metaData.singletonFrame != null, "global".equals(metaData.name), identifier, metaData.name.startsWith("<new-env-")),
+                            initialKind);
         }
     }
 
@@ -585,44 +736,124 @@ public final class FrameSlotChangeMonitor {
         }
     }
 
+    public static void setBooleanAndInvalidate(Frame frame, FrameSlot frameSlot, boolean newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
+        FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
+        if (FastROptions.SharedContexts.getBooleanValue() && info.possibleMultiSlot() && !RContext.isSingle()) {
+            info.setMultiSlot(frame, frameSlot, newValue);
+        } else {
+            frame.setBoolean(frameSlot, newValue);
+            if (info.needsInvalidation()) {
+                info.setValue(newValue, frameSlot);
+            }
+            checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
+        }
+    }
+
+    public static void setBoolean(Frame frame, FrameSlot frameSlot, boolean newValue) {
+        if (FastROptions.SharedContexts.getBooleanValue() && !RContext.isSingle()) {
+            FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
+            if (info.possibleMultiSlot()) {
+                info.setMultiSlot(frame, frameSlot, newValue);
+                return;
+            }
+        }
+        frame.setBoolean(frameSlot, newValue);
+    }
+
     public static void setByteAndInvalidate(Frame frame, FrameSlot frameSlot, byte newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
-        frame.setByte(frameSlot, newValue);
         FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
-        if (info.needsInvalidation()) {
-            info.setValue(newValue, frameSlot);
+        if (FastROptions.SharedContexts.getBooleanValue() && info.possibleMultiSlot() && !RContext.isSingle()) {
+            info.setMultiSlot(frame, frameSlot, newValue);
+        } else {
+            frame.setByte(frameSlot, newValue);
+            if (info.needsInvalidation()) {
+                info.setValue(newValue, frameSlot);
+            }
+            checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
         }
-        checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
+    }
+
+    public static void setByte(Frame frame, FrameSlot frameSlot, byte newValue) {
+        if (FastROptions.SharedContexts.getBooleanValue() && !RContext.isSingle()) {
+            FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
+            if (info.possibleMultiSlot()) {
+                info.setMultiSlot(frame, frameSlot, newValue);
+                return;
+            }
+        }
+        frame.setByte(frameSlot, newValue);
     }
 
     public static void setIntAndInvalidate(Frame frame, FrameSlot frameSlot, int newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
-        frame.setInt(frameSlot, newValue);
         FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
-        if (info.needsInvalidation()) {
-            info.setValue(newValue, frameSlot);
+        if (FastROptions.SharedContexts.getBooleanValue() && info.possibleMultiSlot() && !RContext.isSingle()) {
+            info.setMultiSlot(frame, frameSlot, newValue);
+        } else {
+            frame.setInt(frameSlot, newValue);
+            if (info.needsInvalidation()) {
+                info.setValue(newValue, frameSlot);
+            }
+            checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
         }
-        checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
+    }
+
+    public static void setInt(Frame frame, FrameSlot frameSlot, int newValue) {
+        if (FastROptions.SharedContexts.getBooleanValue() && !RContext.isSingle()) {
+            FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
+            if (info.possibleMultiSlot()) {
+                info.setMultiSlot(frame, frameSlot, newValue);
+                return;
+            }
+        }
+        frame.setInt(frameSlot, newValue);
     }
 
     public static void setDoubleAndInvalidate(Frame frame, FrameSlot frameSlot, double newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
-        frame.setDouble(frameSlot, newValue);
         FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
-        if (info.needsInvalidation()) {
-            info.setValue(newValue, frameSlot);
+        if (FastROptions.SharedContexts.getBooleanValue() && info.possibleMultiSlot() && !RContext.isSingle()) {
+            info.setMultiSlot(frame, frameSlot, newValue);
+        } else {
+            frame.setDouble(frameSlot, newValue);
+            if (info.needsInvalidation()) {
+                info.setValue(newValue, frameSlot);
+            }
+            checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
         }
-        checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
+    }
+
+    public static void setDouble(Frame frame, FrameSlot frameSlot, double newValue) {
+        if (FastROptions.SharedContexts.getBooleanValue() && !RContext.isSingle()) {
+            FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
+            if (info.possibleMultiSlot()) {
+                info.setMultiSlot(frame, frameSlot, newValue);
+                return;
+            }
+        }
+        frame.setDouble(frameSlot, newValue);
     }
 
     public static void setObjectAndInvalidate(Frame frame, FrameSlot frameSlot, Object newValue, boolean isNonLocal, BranchProfile invalidateProfile) {
         assert !ActiveBinding.isActiveBinding(newValue);
-        frame.setObject(frameSlot, newValue);
         FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
-        if (info.needsInvalidation()) {
-            info.setValue(newValue, frameSlot);
+        if (FastROptions.SharedContexts.getBooleanValue() && info.possibleMultiSlot() && !RContext.isSingle()) {
+            info.setMultiSlot(frame, frameSlot, newValue);
+        } else {
+            frame.setObject(frameSlot, newValue);
+            if (info.needsInvalidation()) {
+                info.setValue(newValue, frameSlot);
+            }
+            checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
         }
-        checkAndInvalidate(frame, frameSlot, isNonLocal, invalidateProfile);
     }
 
     public static void setObject(Frame frame, FrameSlot frameSlot, Object newValue) {
+        if (FastROptions.SharedContexts.getBooleanValue() && !RContext.isSingle()) {
+            FrameSlotInfoImpl info = getFrameSlotInfo(frameSlot);
+            if (info.possibleMultiSlot()) {
+                info.setMultiSlot(frame, frameSlot, newValue);
+                return;
+            }
+        }
         frame.setObject(frameSlot, newValue);
     }
 
@@ -641,6 +872,7 @@ public final class FrameSlotChangeMonitor {
      * intended to be used for a non-function frame (and thus will only ever be used for one frame).
      */
     public static synchronized void initializeNonFunctionFrameDescriptor(String name, MaterializedFrame frame) {
+        CompilerAsserts.neverPartOfCompilation();
         frameDescriptors.put(handleBaseNamespaceEnv(frame), new FrameDescriptorMetaData(name, frame));
     }
 
@@ -680,11 +912,61 @@ public final class FrameSlotChangeMonitor {
         return getMetaData(frameDesc) != null;
     }
 
+    /*
+     * This method should be called for frames of all environments on the search path.
+     */
+    public static void handleAllMultiSlots(Frame frame, boolean replicate) {
+        // make a copy avoid potential updates to the array iterated over
+        FrameSlot[] slots = new FrameSlot[frame.getFrameDescriptor().getSlots().size()];
+        slots = frame.getFrameDescriptor().getSlots().toArray(slots);
+        for (int i = 0; i < slots.length; i++) {
+            if (!(slots[i].getIdentifier() instanceof RFrameSlot)) {
+                FrameSlotInfoImpl.handleSearchPathMultiSlot(frame, slots[i], replicate);
+            }
+        }
+    }
+
     public static Object getObject(FrameSlot slot, Frame frame) throws FrameSlotTypeException {
-        return frame.getObject(slot);
+        if (FastROptions.SharedContexts.getBooleanValue() && !RContext.isSingle()) {
+            FrameSlotInfoImpl info = getFrameSlotInfo(slot);
+            if (info.noMultiSlot.isValid()) {
+                return frame.getObject(slot);
+            }
+            Object o;
+            try {
+                o = frame.getObject(slot);
+            } catch (FrameSlotTypeException e) {
+                CompilerDirectives.transferToInterpreter();
+                o = null;
+            }
+            if (!(o instanceof MultiSlotData)) {
+                CompilerDirectives.transferToInterpreter();
+                synchronized (info) {
+                    o = frame.getObject(slot);
+                }
+            }
+            return ((MultiSlotData) o).get(RContext.getInstance().getMultiSlotInd());
+        } else {
+            return frame.getObject(slot);
+        }
     }
 
     public static Object getValue(FrameSlot slot, Frame frame) {
-        return frame.getValue(slot);
+        if (FastROptions.SharedContexts.getBooleanValue() && !RContext.isSingle()) {
+            FrameSlotInfoImpl info = getFrameSlotInfo(slot);
+            if (info.noMultiSlot.isValid()) {
+                return frame.getValue(slot);
+            }
+            Object o = frame.getValue(slot);
+            if (!(o instanceof MultiSlotData)) {
+                CompilerDirectives.transferToInterpreter();
+                synchronized (info) {
+                    o = frame.getValue(slot);
+                }
+            }
+            return ((MultiSlotData) o).get(RContext.getInstance().getMultiSlotInd());
+        } else {
+            return frame.getValue(slot);
+        }
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/NSBaseMaterializedFrame.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/NSBaseMaterializedFrame.java
index af7d7af6ec7e74c8c527523e9c58216cd6736c29..e7006cbd06fb44eee613d651621de8cd08e5c778 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/NSBaseMaterializedFrame.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/frame/NSBaseMaterializedFrame.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -60,7 +60,7 @@ public final class NSBaseMaterializedFrame implements MaterializedFrame {
     }
 
     public void updateGlobalFrame(MaterializedFrame globalFrame) {
-        RArguments.setEnclosingFrame(this, globalFrame);
+        RArguments.setEnclosingFrame(this, globalFrame, true);
     }
 
     public FrameDescriptor getMarkerFrameDescriptor() {
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index b612947eda43f38e2abceae2556c11b0d781adef..492004a017ebcd486b15ecc4a2902cf9172876d3 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -130402,6 +130402,22 @@ a b c d e
 #{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/channels9.R") }
 [1]  TRUE FALSE
 
+##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
+#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing1.R") }
+[1] 42  7
+
+##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
+#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing2.R") }
+[1] "object 'x' not found"
+
+##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
+#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing3.R") }
+[1] 42  7
+
+##com.oracle.truffle.r.test.library.fastr.TestChannels.runRSourceTests#
+#{ source("mxbuild/com.oracle.truffle.r.test/bin/com/oracle/truffle/r/test/channels/R/sharing4.R") }
+[1] 24 42
+
 ##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEval#
 #if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { .fastr.interop.eval('application/x-r', '1') }
 [1] 1
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing1.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing1.R
new file mode 100644
index 0000000000000000000000000000000000000000..5a96c5964206e95944672aad6f548b19288dc56f
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing1.R
@@ -0,0 +1,14 @@
+# test remote update in global space - values should remain distinct
+
+if (length(grep("FastR", R.Version()$version.string)) == 1) {
+    ch1 <- .fastr.channel.create(1L)
+    code <- "ch2 <- .fastr.channel.get(1L); x <- 7; .fastr.channel.send(ch2, x)"
+    x <- 42
+    cx <- .fastr.context.spawn(code)
+    y <- .fastr.channel.receive(ch1)
+    .fastr.context.join(cx)
+    .fastr.channel.close(ch1)
+    print(c(x, y))
+} else {
+    print(c(42L, 7L))
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing2.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing2.R
new file mode 100644
index 0000000000000000000000000000000000000000..3c02fba5abc04a0d0c663d5c715828f69efde269
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing2.R
@@ -0,0 +1,18 @@
+# test subsequent remote updates in global space - second time value should have been reset
+
+if (length(grep("FastR", R.Version()$version.string)) == 1) {
+    ch1 <- .fastr.channel.create(1L)
+    code <- "ch2 <- .fastr.channel.get(1L); x <- 7; .fastr.channel.send(ch2, x)"
+    x <- 42
+    cx <- .fastr.context.spawn(code)
+    y <- .fastr.channel.receive(ch1)
+    .fastr.context.join(cx)
+    code <- "ch2 <- .fastr.channel.get(1L); res <- tryCatch(z <- x, error=function(e) e); .fastr.channel.send(ch2, res[[1]])"
+    cx <- .fastr.context.spawn(code)
+    y <- .fastr.channel.receive(ch1)
+    .fastr.context.join(cx)    
+    .fastr.channel.close(ch1)
+    print(y)
+} else {
+    print("object 'x' not found")
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing3.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing3.R
new file mode 100644
index 0000000000000000000000000000000000000000..ec10067a70355cc808f00d8dbb2eec40c0b4633e
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing3.R
@@ -0,0 +1,15 @@
+# test remote update in base space - values should remain distinct
+
+if (length(grep("FastR", R.Version()$version.string)) == 1) {
+    ch1 <- .fastr.channel.create(1L)
+	# use an obscure name so it doesn't clash with other tests
+    code <- "ch2 <- .fastr.channel.get(1L); assign('tmp59857', 7, env=baseenv()); .fastr.channel.send(ch2, get('tmp59857', env=baseenv(), inherits=F))"
+    assign('tmp59857', 42, env=baseenv())
+    cx <- .fastr.context.spawn(code)
+    y <- .fastr.channel.receive(ch1)
+    .fastr.context.join(cx)
+    .fastr.channel.close(ch1)
+    print(c(get('tmp59857', env=baseenv(), inherits=F), y))
+} else {
+    print(c(42L, 7L))
+}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing4.R b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing4.R
new file mode 100644
index 0000000000000000000000000000000000000000..147da5fcf5939daa2e22f3a78696a799cbd6795a
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/channels/R/sharing4.R
@@ -0,0 +1,23 @@
+# test access to global environment with multiple context instantiations varying context number
+
+if (length(grep("FastR", R.Version()$version.string)) == 1) {
+    ch1 <- .fastr.channel.create(1L)
+    code <- "ch2 <- .fastr.channel.get(1L); x <- .fastr.channel.receive(ch2); .fastr.channel.send(ch2, x)"
+    x <- 7
+    # create one child context
+    cx <- .fastr.context.spawn(code)
+    .fastr.channel.send(ch1, 7)
+    y <- .fastr.channel.receive(ch1)
+    .fastr.context.join(cx)
+    # create two child contexts
+    cx <- .fastr.context.spawn(rep(code, 2))
+    .fastr.channel.send(ch1, 42)
+    .fastr.channel.send(ch1, 24)
+    y <- .fastr.channel.receive(ch1)
+    z <- .fastr.channel.receive(ch1)
+    
+    .fastr.channel.close(ch1)
+    print(sort(c(y, z)))
+} else {
+    print(c(24L, 42L))
+}