diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 08b9eaa9ab0086abccad37f837a643d8ccff7b21..be70203b89111b5f4efcf6dd7c6b29172e53723c 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -152,11 +152,11 @@ final class REngine implements Engine, Engine.Timings {
         this.globalFrame = stateREnvironment.getGlobalFrame();
         this.startTime = System.nanoTime();
         if (context.getKind() == RContext.ContextKind.SHARE_NOTHING) {
-            initializeShared();
+            initializeNonShared();
         }
     }
 
-    private void initializeShared() {
+    private void initializeNonShared() {
         suppressWarnings = true;
         MaterializedFrame baseFrame = RRuntime.createNonFunctionFrame("base");
         REnvironment.baseInitialize(baseFrame, globalFrame);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index d676fd3d8a85df882e7ee53ff72583f593d94eaf..e2a1b3c16c740ab471f92fce1816aadeaa72dc7e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -98,6 +98,7 @@ import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
+import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RFastPathNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -294,7 +295,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             S3Args s3Args;
             RFunction resultFunction;
             if (implicitTypeProfile.profile(type != null)) {
-                Result result = dispatchLookup.execute(frame, builtin.getGenericName(), type, null, frame.materialize(), null);
+                Result result = dispatchLookup.execute(frame, builtin.getGenericName(), type, null, frame.materialize(), REnvironment.baseEnv().getFrame());
                 if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) {
                     s3Args = null;
                 } else {
@@ -331,7 +332,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         S3Args s3Args;
         RFunction resultFunction;
         if (implicitTypeProfile.profile(type != null)) {
-            Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), null);
+            Result result = dispatchLookup.execute(frame, builtin.getName(), type, null, frame.materialize(), REnvironment.baseEnv().getFrame());
             if (resultIsBuiltinProfile.profile(result.function.isBuiltin())) {
                 s3Args = null;
             } else {
@@ -403,13 +404,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         RStringVector typeX = classHierarchyNodeX.execute(promiseHelperNode.checkEvaluate(frame, args[typeXIdx]));
         Result resultX = null;
         if (implicitTypeProfileX.profile(typeX != null)) {
-            resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), null);
+            resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), REnvironment.baseEnv().getFrame());
         }
         Result resultY = null;
         if (args.length > 1 && dispatch == RDispatch.OPS_GROUP_GENERIC) {
             RStringVector typeY = classHierarchyNodeY.execute(promiseHelperNode.checkEvaluate(frame, args[1]));
             if (implicitTypeProfileY.profile(typeY != null)) {
-                resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), null);
+                resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), REnvironment.baseEnv().getFrame());
             }
         }
 
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 48e0fcf60fc82ed3b4217fa0518840240f400507..4cf0176368423fa63a183ba02c9c5747a1331e2a 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
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.regex.Pattern;
 
 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.MaterializedFrame;
@@ -112,26 +113,16 @@ public abstract class REnvironment extends RAttributeStorage {
     }
 
     public static final class ContextStateImpl implements RContext.ContextState {
-        private SearchPath searchPath;
         private final MaterializedFrame globalFrame;
-        private Base baseEnv;
-        private REnvironment namespaceRegistry;
-        private MaterializedFrame parentGlobalFrame; // SHARED_PARENT_RW only
+        @CompilationFinal private Base baseEnv;
+        @CompilationFinal private REnvironment namespaceRegistry;
+        @CompilationFinal private SearchPath searchPath;
+        @CompilationFinal private MaterializedFrame parentGlobalFrame; // SHARED_PARENT_RW only
 
         private ContextStateImpl(MaterializedFrame globalFrame) {
             this.globalFrame = globalFrame;
         }
 
-        private void initialize(SearchPath searchPathA) {
-            this.searchPath = searchPathA;
-        }
-
-        private void initialize(SearchPath searchPathA, Base baseEnvA, REnvironment namespaceRegistryA) {
-            this.searchPath = searchPathA;
-            this.baseEnv = baseEnvA;
-            this.namespaceRegistry = namespaceRegistryA;
-        }
-
         public REnvironment getGlobalEnv() {
             return RArguments.getEnvironment(globalFrame);
         }
@@ -156,18 +147,6 @@ public abstract class REnvironment extends RAttributeStorage {
             return namespaceRegistry;
         }
 
-        private void setSearchPath(SearchPath searchPath) {
-            this.searchPath = searchPath;
-        }
-
-        private void setBaseEnv(Base baseEnv) {
-            this.baseEnv = baseEnv;
-        }
-
-        private void setNamespaceRegistry(REnvironment namespaceRegistry) {
-            this.namespaceRegistry = namespaceRegistry;
-        }
-
         @Override
         public RContext.ContextState initialize(RContext context) {
             setupContext(this, context, globalFrame);
@@ -183,6 +162,15 @@ public abstract class REnvironment extends RAttributeStorage {
         public static ContextStateImpl newContextState() {
             return new ContextStateImpl(RRuntime.createNonFunctionFrame("global"));
         }
+
+        public void initialize(Base newBaseEnv, REnvironment newNamespaceRegistry, SearchPath newSearchPath) {
+            assert baseEnv == null;
+            assert namespaceRegistry == null;
+            assert searchPath == null;
+            this.baseEnv = newBaseEnv;
+            this.namespaceRegistry = newNamespaceRegistry;
+            this.searchPath = newSearchPath;
+        }
     }
 
     public static class PutException extends RErrorException {
@@ -301,14 +289,12 @@ public abstract class REnvironment extends RAttributeStorage {
         // TODO if namespaceRegistry is ever used in an eval an internal env won't suffice.
         REnvironment namespaceRegistry = RDataFactory.createInternalEnv();
         ContextStateImpl state = RContext.getInstance().stateREnvironment;
-        state.setNamespaceRegistry(namespaceRegistry);
         Base baseEnv = new Base(baseFrame, initialGlobalFrame);
         namespaceRegistry.safePut("base", baseEnv.namespaceEnv);
 
         Global globalEnv = new Global(initialGlobalFrame);
         RArguments.initializeEnclosingFrame(initialGlobalFrame, baseFrame);
-        state.setBaseEnv(baseEnv);
-        state.setSearchPath(initSearchList(globalEnv));
+        state.initialize(baseEnv, namespaceRegistry, initSearchList(globalEnv));
     }
 
     /**
@@ -341,7 +327,7 @@ public abstract class REnvironment extends RAttributeStorage {
                 SearchPath searchPath = initSearchList(prevGlobalEnv);
                 searchPath.updateGlobal(newGlobalEnv);
                 parentState.getBaseEnv().safePut(".GlobalEnv", newGlobalEnv);
-                contextState.initialize(searchPath, parentBaseEnv, parentState.getNamespaceRegistry());
+                contextState.initialize(parentBaseEnv, parentState.getNamespaceRegistry(), searchPath);
                 contextState.parentGlobalFrame = prevGlobalFrame;
                 break;
             }
@@ -369,13 +355,12 @@ public abstract class REnvironment extends RAttributeStorage {
                 newNamespaceRegistry.safePut("base", newBaseEnv.namespaceEnv);
                 newBaseEnv.safePut(".GlobalEnv", newGlobalEnv);
                 SearchPath newSearchPath = initSearchList(newGlobalEnv);
-                contextState.initialize(newSearchPath, newBaseEnv, newNamespaceRegistry);
+                contextState.initialize(newBaseEnv, newNamespaceRegistry, newSearchPath);
                 break;
             }
 
             case SHARE_NOTHING: {
                 // SHARE_NOTHING: baseInitialize takes care of everything
-                contextState.initialize(new SearchPath());
                 break;
             }
 
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 512d438c1f484e3c9c335261017e16a1a528a6e3..ce4e31970c1c8b676edc3d5efb2b65ba18b0450b 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
@@ -72066,6 +72066,34 @@ $c
 [1] 5
 
 
+##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
+#terms(x~z)[1];
+x ~ z
+attr(,"variables")
+list(x, z)
+attr(,"factors")
+  z
+x 0
+z 1
+attr(,"term.labels")
+[1] "z"
+attr(,"order")
+[1] 1
+attr(,"intercept")
+[1] 1
+attr(,"response")
+[1] 1
+attr(,".Environment")
+<environment: R_GlobalEnv>
+
+##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
+#{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x+x; }
+[1] 42
+
+##com.oracle.truffle.r.test.functions.TestS3Dispatch.testGenericDispatchThroughMethodsTable#
+#{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x[[99]]; }
+[1] 42
+
 ##com.oracle.truffle.r.test.functions.TestS3Dispatch.testMathGroupDispatch#
 #{x<--7;class(x)<-"foo";Math.foo<-function(z){-z;};log(x);}
 [1] 7
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
index f1223309640871c284afd162fd3feb91e37cdd01..bc847b5fab907eefbb96f4edb503053990199b97 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestS3Dispatch.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -134,6 +134,14 @@ public class TestS3Dispatch extends TestRBase {
         assertEval("f.default<-function(abc, bbb, ...)list(abc, bbb, ...); f<-function(x,...)UseMethod('f'); f(13, ab=42, b=1, c=5);");
     }
 
+    @Test
+    public void testGenericDispatchThroughMethodsTable() {
+        // Note: `[.term` is "private" in stats, but it has entry in __S3MethodsTable__
+        assertEval("terms(x~z)[1];");
+        assertEval("{ assign('Ops.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x+x; }");
+        assertEval("{ assign('[[.myclass', function(a,b) 42, envir=.__S3MethodsTable__.); x<-1; class(x)<-'myclass'; x[[99]]; }");
+    }
+
     @Override
     public String getTestDir() {
         return "functions/S3";