diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
index a7a17f8209246e587408d1f6731774faf9faf28b..e8547dc985cbad602368033b7b425c51b9b78a82 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java
@@ -33,13 +33,10 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
-import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
@@ -63,7 +60,6 @@ import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.CallerFrameClosure;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -260,9 +256,6 @@ public class GetFunctions {
         @Child private TypeFromModeNode typeFromMode = TypeFromModeNodeGen.create();
         @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2);
 
-        private final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame");
-        private final CallerFrameClosure setNeedsCallerFrameClosure = new SetNeedsCallerFrameFlag(needsNoCallerFrame);
-
         static {
             Casts casts = new Casts(MGet.class);
             casts.arg("x").mustBe(stringValue()).asStringVector();
@@ -379,13 +372,12 @@ public class GetFunctions {
         }
 
         private Object call(VirtualFrame frame, RFunction ifnFunc, String x) {
-            if (needsNoCallerFrame.isValid() && ((RRootNode) ifnFunc.getRootNode()).containsDispatch()) {
-                needsNoCallerFrame.invalidate();
+            if (((RRootNode) ifnFunc.getRootNode()).containsDispatch()) {
+                callCache.setNeedsCallerFrame();
             }
-            Object callerFrameObject = needsNoCallerFrame.isValid() ? setNeedsCallerFrameClosure : frame.materialize();
             FormalArguments formals = ((RRootNode) ifnFunc.getRootNode()).getFormalArguments();
             RArgsValuesAndNames args = new RArgsValuesAndNames(new Object[]{x}, ArgumentsSignature.empty(1));
-            return callCache.execute(frame, ifnFunc, RCaller.create(frame, RCallerHelper.createFromArguments(ifnFunc, args)), callerFrameObject, new Object[]{x}, formals.getSignature(),
+            return callCache.execute(frame, ifnFunc, RCaller.create(frame, RCallerHelper.createFromArguments(ifnFunc, args)), new Object[]{x}, formals.getSignature(),
                             ifnFunc.getEnclosingFrame(), null);
         }
 
@@ -404,24 +396,5 @@ public class GetFunctions {
             return value;
         }
 
-        private class SetNeedsCallerFrameFlag extends CallerFrameClosure {
-
-            private final Assumption needsNoCallerFrame;
-
-            SetNeedsCallerFrameFlag(Assumption needsNoCallerFrame) {
-                this.needsNoCallerFrame = needsNoCallerFrame;
-            }
-
-            @Override
-            public void setNeedsCallerFrame() {
-                needsNoCallerFrame.invalidate();
-            }
-
-            @Override
-            public MaterializedFrame getMaterializedCallerFrame() {
-                return null;
-            }
-
-        }
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
index a217ccfdb3038dc7935044633c912fb8466c7c91..7163f0f9bdce97762ca7b848cc3bb87265f5e467 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
@@ -49,7 +49,6 @@ import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSerialize;
-import com.oracle.truffle.r.runtime.CallerFrameClosure;
 import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -254,7 +253,7 @@ public class HiddenInternalFunctions {
                 RSerialize.CallHook callHook = new RSerialize.CallHook() {
                     @Override
                     public Object eval(Object arg) {
-                        return callCache.execute(SubstituteVirtualFrame.create(frame), envhook, RCaller.create(frame, getOriginalCall()), new CallerFrameClosure.Dummy(0), new Object[]{arg}, null);
+                        return callCache.execute(SubstituteVirtualFrame.create(frame), envhook, RCaller.create(frame, getOriginalCall()), new Object[]{arg}, null);
                     }
                 };
                 String functionName = ReadVariableNode.getSlowPathEvaluationName();
@@ -386,7 +385,7 @@ public class HiddenInternalFunctions {
             RSerialize.CallHook callHook = new RSerialize.CallHook() {
                 @Override
                 public Object eval(Object arg) {
-                    return callCache.execute(SubstituteVirtualFrame.create(frame), hook, RCaller.create(frame, getOriginalCall()), null, new Object[]{arg}, null);
+                    return callCache.execute(SubstituteVirtualFrame.create(frame), hook, RCaller.create(frame, getOriginalCall()), new Object[]{arg}, null);
                 }
             };
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
index c9d12275d3cd53f8f5576e3e264c7a55b4763552..4e58a26827823130d05262542f7a91929bce0238 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java
@@ -32,7 +32,6 @@ import com.oracle.truffle.r.nodes.function.call.CallRFunctionNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.CallerFrameClosure;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -107,7 +106,7 @@ public abstract class UpdateSlot extends RBuiltinNode.Arg3 {
             if (cached.profile(currentFunction == checkSlotAssignFunction)) {
                 // TODO: technically, someone could override checkAtAssignment function and access
                 // the caller, but it's rather unlikely
-                checkAtAssignmentCall.execute(frame, checkSlotAssignFunction, RCaller.createInvalid(frame), null, new Object[]{objClass, name, valClass}, SIGNATURE,
+                checkAtAssignmentCall.execute(frame, checkSlotAssignFunction, RCaller.createInvalid(frame), new Object[]{objClass, name, valClass}, SIGNATURE,
                                 checkSlotAssignFunction.getEnclosingFrame(), null);
             } else {
                 // slow path
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
index ef7648287641e87a826d3734a6f660242ddb6985..fe03a9b9a5f5f2e6606b012a513f4578757b619e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.runtime.RArguments.DispatchArgs;
 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.CallerFrameClosure;
 import com.oracle.truffle.r.runtime.builtins.FastPathFactory;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
@@ -265,8 +264,7 @@ public abstract class CallMatcherNode extends RBaseNode {
                     Supplier<RSyntaxElement> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature);
                     RCaller caller = genFunctionName == null ? RCaller.createInvalid(frame, parent) : RCaller.create(frame, parent, argsSupplier);
                     try {
-                        return call.execute(frame, cachedFunction, caller, null, reorderedArgs, matchedArgs.getSignature(), cachedFunction.getEnclosingFrame(),
-                                        dispatchArgs);
+                        return call.execute(frame, cachedFunction, caller, reorderedArgs, matchedArgs.getSignature(), cachedFunction.getEnclosingFrame(), dispatchArgs);
                     } finally {
                         visibility.executeAfterCall(frame, caller);
                     }
@@ -346,7 +344,7 @@ public abstract class CallMatcherNode extends RBaseNode {
                             : RCaller.create(frame, RCallerHelper.createFromArguments(genFunctionName,
                                             new RArgsValuesAndNames(reorderedArgs.getArguments(), ArgumentsSignature.empty(reorderedArgs.getLength()))));
             try {
-                return call.execute(frame, function, caller, new CallerFrameClosure.Dummy(3), reorderedArgs.getArguments(), reorderedArgs.getSignature(), function.getEnclosingFrame(), dispatchArgs);
+                return call.execute(frame, function, caller, reorderedArgs.getArguments(), reorderedArgs.getSignature(), function.getEnclosingFrame(), dispatchArgs);
             } finally {
                 visibility.executeAfterCall(frame, caller);
             }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java
index 6e4ecf5de1af949aeac0a8f51c6ae19209b49937..1583d0222e7a1d285baad422132c346c1874ebef 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.function;
 
+import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.frame.Frame;
@@ -47,33 +48,41 @@ public final class GetCallerFrameNode extends RBaseNode {
 
     public MaterializedFrame execute(Frame frame) {
         Object callerFrameObject = RArguments.getCallerFrame(frame);
+        MaterializedFrame mCallerFrame;
         if (callerFrameObject instanceof CallerFrameClosure) {
-            CallerFrameClosure closure = (CallerFrameClosure) callerFrameObject;
             if (!slowPathInitialized) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 slowPathInitialized = true;
             }
-            notifyCallers(closure);
+            CallerFrameClosure closure = (CallerFrameClosure) callerFrameObject;
+
+            // inform the responsible call node to create a caller frame
+            closure.setNeedsCallerFrame();
+
+            // if interpreted, we will have a materialized frame in the closure
             MaterializedFrame materializedCallerFrame = closure.getMaterializedCallerFrame();
             if (materializedCallerFrame != null) {
+                CompilerAsserts.neverPartOfCompilation();
                 return materializedCallerFrame;
             }
             RError.performanceWarning("slow caller frame access");
             // for now, get it on the very slow path
             Frame callerFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE);
             if (callerFrame != null) {
-                return callerFrame.materialize();
-            } else {
-                topLevelProfile.enter();
-                // S3 method can be dispatched from top-level where there is no caller frame
-                return frame.materialize();
+                mCallerFrame = callerFrame.materialize();
             }
         }
-        return (MaterializedFrame) callerFrameObject;
+        if (callerFrameObject == null) {
+            // S3 method can be dispatched from top-level where there is no caller frame
+            // Since RArguments does not allow to create arguments with a 'null' caller frame, this
+            // must be the top level case.
+            topLevelProfile.enter();
+            return frame.materialize();
+        } else {
+            mCallerFrame = (MaterializedFrame) callerFrameObject;
+        }
+        assert callerFrameObject instanceof MaterializedFrame;
+        return mCallerFrame;
     }
 
-    private static void notifyCallers(CallerFrameClosure callerFrameObject) {
-        // inform the responsible call node to create a caller frame
-        callerFrameObject.setNeedsCallerFrame();
-    }
 }
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 f403228b90cdd8ecd60eed11bd43745ff419bd4f..f1996378bde793255c0bc50eef27cb8fa4343908 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
@@ -31,7 +31,6 @@ 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.RootCallTarget;
-import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.NodeChild;
@@ -70,8 +69,7 @@ import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.Arguments;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
-import com.oracle.truffle.r.runtime.interop.Foreign2R;
-import com.oracle.truffle.r.runtime.interop.R2Foreign;
+import com.oracle.truffle.r.runtime.CallerFrameClosure;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RArguments.S3Args;
 import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments;
@@ -83,7 +81,6 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.RVisibility;
-import com.oracle.truffle.r.runtime.CallerFrameClosure;
 import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.builtins.FastPathFactory;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
@@ -102,7 +99,9 @@ import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
+import com.oracle.truffle.r.runtime.interop.Foreign2R;
 import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen;
+import com.oracle.truffle.r.runtime.interop.R2Foreign;
 import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RFastPathNode;
@@ -155,16 +154,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
     // needed for INTERNAL_GENERIC calls:
     @Child private FunctionDispatch internalDispatchCall;
 
-    // TODO remove; kept just for compatibility
-    private final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame");
-
-    // TODO remove; kept just for compatibility
-    public boolean setNeedsCallerFrame() {
-        boolean value = !needsNoCallerFrame.isValid();
-        needsNoCallerFrame.invalidate();
-        return value;
-    }
-
     protected RCaller createCaller(VirtualFrame frame, RFunction function) {
         if (explicitArgs == null) {
             return RCaller.create(frame, this);
@@ -959,6 +948,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         private final RootCallTarget cachedTarget;
         private final FastPathFactory fastPathFactory;
         private final RVisibility fastPathVisibility;
+        private final boolean containsDispatch;
 
         DispatchedCallNode(RootCallTarget cachedTarget, RCallNode originalCall) {
             super(originalCall);
@@ -968,9 +958,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             this.fastPath = fastPathFactory == null ? null : fastPathFactory.create();
             this.fastPathVisibility = fastPathFactory == null ? null : fastPathFactory.getVisibility();
             this.visibility = fastPathFactory == null ? null : SetVisibilityNode.create();
-            if (root.containsDispatch()) {
-                originalCall.setNeedsCallerFrame();
-            }
+            this.containsDispatch = root.containsDispatch();
         }
 
         @Override
@@ -993,10 +981,12 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                 if (needsSplitting(cachedTarget)) {
                     call.getCallNode().cloneCallTarget();
                 }
+                if (containsDispatch) {
+                    call.setNeedsCallerFrame();
+                }
             }
 
-            return call.execute(frame, function, originalCall.createCaller(frame, function), null, orderedArguments.getArguments(), orderedArguments.getSignature(),
-                            function.getEnclosingFrame(), s3Args);
+            return call.execute(frame, function, originalCall.createCaller(frame, function), orderedArguments.getArguments(), orderedArguments.getSignature(), function.getEnclosingFrame(), s3Args);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionBaseNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f8ca2212e387c8966beee4f1da48f13b0159958
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionBaseNode.java
@@ -0,0 +1,60 @@
+package com.oracle.truffle.r.nodes.function.call;
+
+import com.oracle.truffle.api.Assumption;
+import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.MaterializedFrame;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.runtime.CallerFrameClosure;
+
+public abstract class CallRFunctionBaseNode extends Node {
+
+    protected final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame");
+    protected final CallerFrameClosure invalidateNoCallerFrame = new InvalidateNoCallerFrame(needsNoCallerFrame);
+
+    public boolean setNeedsCallerFrame() {
+        boolean value = !needsNoCallerFrame.isValid();
+        needsNoCallerFrame.invalidate();
+        return value;
+    }
+
+    private Object getCallerFrameClosure(VirtualFrame callerFrame) {
+        if (CompilerDirectives.inInterpreter()) {
+            return new InvalidateNoCallerFrame(needsNoCallerFrame, callerFrame.materialize());
+        }
+        return invalidateNoCallerFrame;
+    }
+
+    protected final Object getCallerFrameObject(VirtualFrame callerFrame) {
+        return needsNoCallerFrame.isValid() ? getCallerFrameClosure(callerFrame) : callerFrame.materialize();
+    }
+
+    public static final class InvalidateNoCallerFrame extends CallerFrameClosure {
+
+        private final Assumption needsNoCallerFrame;
+        private final MaterializedFrame frame;
+
+        protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame) {
+            this.needsNoCallerFrame = needsNoCallerFrame;
+            this.frame = null;
+        }
+
+        protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame, MaterializedFrame frame) {
+            this.needsNoCallerFrame = needsNoCallerFrame;
+            this.frame = frame;
+        }
+
+        @Override
+        public void setNeedsCallerFrame() {
+            needsNoCallerFrame.invalidate();
+        }
+
+        @Override
+        public MaterializedFrame getMaterializedCallerFrame() {
+            return frame;
+        }
+
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java
index e871bee0dbe0c26401f532ac1bca9b53714878a4..43fd6ecc99ca99dba05e16744f0ad1da6159c160 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java
@@ -30,7 +30,6 @@ import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.DirectCallNode;
 import com.oracle.truffle.api.nodes.IndirectCallNode;
-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.nodes.function.visibility.SetVisibilityNode;
@@ -41,7 +40,7 @@ import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.data.RFunction;
 
 @NodeInfo(cost = NodeCost.NONE)
-public abstract class CallRFunctionCachedNode extends Node {
+public abstract class CallRFunctionCachedNode extends CallRFunctionBaseNode {
 
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
@@ -51,14 +50,14 @@ public abstract class CallRFunctionCachedNode extends Node {
         this.cacheLimit = cacheLimit;
     }
 
-    public final Object execute(VirtualFrame frame, RFunction function, RCaller call, Object callerFrameObject, Object[] evaluatedArgs, DispatchArgs dispatchArgs) {
-        Object[] callArgs = RArguments.create(function, call, callerFrameObject, evaluatedArgs, dispatchArgs);
+    public final Object execute(VirtualFrame frame, RFunction function, RCaller call, Object[] evaluatedArgs, DispatchArgs dispatchArgs) {
+        Object[] callArgs = RArguments.create(function, call, getCallerFrameObject(frame), evaluatedArgs, dispatchArgs);
         return execute(frame, function.getTarget(), callArgs, call);
     }
 
-    public final Object execute(VirtualFrame frame, RFunction function, RCaller call, Object callerFrameObject, Object[] evaluatedArgs,
+    public final Object execute(VirtualFrame frame, RFunction function, RCaller call, Object[] evaluatedArgs,
                     ArgumentsSignature suppliedSignature, MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) {
-        Object[] callArgs = RArguments.create(function, call, callerFrameObject, evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs);
+        Object[] callArgs = RArguments.create(function, call, getCallerFrameObject(frame), evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs);
         return execute(frame, function.getTarget(), callArgs, call);
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
index d8585b338bf6ebe57652bb451e125348009c062a..432d72b8379bb61837877f537cc3148c5ff297df 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java
@@ -22,33 +22,26 @@
  */
 package com.oracle.truffle.r.nodes.function.call;
 
-import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CallTarget;
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.Truffle;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.DirectCallNode;
-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.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
-import com.oracle.truffle.r.runtime.CallerFrameClosure;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RArguments.DispatchArgs;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.data.RFunction;
 
 @NodeInfo(cost = NodeCost.NONE)
-public final class CallRFunctionNode extends Node {
+public final class CallRFunctionNode extends CallRFunctionBaseNode {
 
     @Child private DirectCallNode callNode;
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-    private final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame");
-    private final CallerFrameClosure invalidateNoCallerFrame = new InvalidateNoCallerFrame(needsNoCallerFrame);
-
     private CallRFunctionNode(CallTarget callTarget) {
         this.callNode = Truffle.getRuntime().createDirectCallNode(callTarget);
     }
@@ -57,10 +50,9 @@ public final class CallRFunctionNode extends Node {
         return new CallRFunctionNode(callTarget);
     }
 
-    public Object execute(VirtualFrame frame, RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature,
+    public Object execute(VirtualFrame frame, RFunction function, RCaller caller, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature,
                     MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) {
-        Object callerFrameObject = needsNoCallerFrame.isValid() ? getCallerFrameObject(frame) : frame.materialize();
-        Object[] callArgs = RArguments.create(function, caller, callerFrameObject, evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs);
+        Object[] callArgs = RArguments.create(function, caller, getCallerFrameObject(frame), evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs);
         try {
             return callNode.call(callArgs);
         } finally {
@@ -68,13 +60,6 @@ public final class CallRFunctionNode extends Node {
         }
     }
 
-    private Object getCallerFrameObject(VirtualFrame callerFrame) {
-        if (CompilerDirectives.inInterpreter()) {
-            return new InvalidateNoCallerFrame(needsNoCallerFrame, callerFrame.materialize());
-        }
-        return invalidateNoCallerFrame;
-    }
-
     public DirectCallNode getCallNode() {
         return callNode;
     }
@@ -98,31 +83,4 @@ public final class CallRFunctionNode extends Node {
             SetVisibilityNode.executeAfterCallSlowPath(callerFrame, caller);
         }
     }
-
-    public static final class InvalidateNoCallerFrame extends CallerFrameClosure {
-
-        private final Assumption needsNoCallerFrame;
-        private final MaterializedFrame frame;
-
-        protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame) {
-            this.needsNoCallerFrame = needsNoCallerFrame;
-            this.frame = null;
-        }
-
-        protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame, MaterializedFrame frame) {
-            this.needsNoCallerFrame = needsNoCallerFrame;
-            this.frame = frame;
-        }
-
-        @Override
-        public void setNeedsCallerFrame() {
-            needsNoCallerFrame.invalidate();
-        }
-
-        @Override
-        public MaterializedFrame getMaterializedCallerFrame() {
-            return frame;
-        }
-
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
index 3a5cbd249e66e858b870df793b35e5a3f99a3779..1803e88efbfda4b92f6f6c4b95f1097ec6477f8b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
@@ -131,8 +131,7 @@ abstract class LoadMethod extends RBaseNode {
             if (cached.profile(currentFunction == loadMethodFunction)) {
                 // TODO: technically, someone could override loadMethod function and access the
                 // caller, but it's rather unlikely
-                ret = (RFunction) loadMethodCall.execute(frame, loadMethodFunction, caller, null,
-                                new Object[]{fdef, fname, REnvironment.frameToEnvironment(frame.materialize())}, SIGNATURE,
+                ret = (RFunction) loadMethodCall.execute(frame, loadMethodFunction, caller, new Object[]{fdef, fname, REnvironment.frameToEnvironment(frame.materialize())}, SIGNATURE,
                                 loadMethodFunction.getEnclosingFrame(), null);
             } else {
                 // slow path
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java
index f642e50181a719ebb39b484a2537349075e57f1b..c47abc9df712b87da12d7cbcddb705ac8c612dcc 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java
@@ -25,7 +25,6 @@ package com.oracle.truffle.r.runtime;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 
 public abstract class CallerFrameClosure {
-// public static final CallerFrameClosure DUMMY = new Dummy();
 
     /**
      * Inform the call node to subsequently provide the caller frame.
@@ -37,23 +36,4 @@ public abstract class CallerFrameClosure {
      */
     public abstract MaterializedFrame getMaterializedCallerFrame();
 
-    public static class Dummy extends CallerFrameClosure {
-
-        private final int id;
-
-        public Dummy(int id) {
-            this.id = id;
-        }
-
-        @Override
-        public void setNeedsCallerFrame() {
-            // do nothing
-        }
-
-        @Override
-        public MaterializedFrame getMaterializedCallerFrame() {
-            return null;
-        }
-
-    }
 }