diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
index 2e89f81f2cc2f6935cf32ae8f443fb39f875c702..1bd1775303472c90c454eba31e2e3e33afb6e4af 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BrowserFunctions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, 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
@@ -45,7 +45,6 @@ import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
@@ -96,7 +95,7 @@ public class BrowserFunctions {
                             CompilerDirectives.transferToInterpreterAndInvalidate();
                             getCallerFrame = insert(new GetCallerFrameNode());
                         }
-                        actualFrame = SubstituteVirtualFrame.create(getCallerFrame.execute(mFrame));
+                        actualFrame = getCallerFrame.execute(mFrame);
                         caller = caller.getParent();
                     }
                     doPrint(caller);
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 0815326dbc0244132ec05babc62c8a8519e24984..938fc86868755f44f9c7bff182d27f84938a8856 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
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995-2012, The R Core Team
  * Copyright (c) 2003, The R Foundation
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -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.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.Closure;
@@ -253,7 +252,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 Object[]{arg}, null);
+                        return callCache.execute(frame, envhook, RCaller.create(frame, getOriginalCall()), new Object[]{arg}, null);
                     }
                 };
                 String functionName = ReadVariableNode.getSlowPathEvaluationName();
@@ -385,7 +384,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()), new Object[]{arg}, null);
+                    return callCache.execute(frame, hook, RCaller.create(frame, getOriginalCall()), new Object[]{arg}, null);
                 }
             };
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
index d8878a581e648e7b57d55a82bf0a6ee97d037a46..12679e0c86560b1293387390f1fc5becd419a7b5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, 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
@@ -31,7 +31,6 @@ import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.data.Closure;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -61,7 +60,7 @@ public abstract class InlineCacheNode extends RBaseNode {
         if (isVirtualFrameProfile.profile(frame instanceof VirtualFrame)) {
             vf = (VirtualFrame) frame;
         } else {
-            vf = SubstituteVirtualFrame.create(frame.materialize());
+            vf = frame.materialize();
         }
 
         // Use a closure to notify the root node that a new node has just been inserted. The
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
index 45f7c7172620825a5482dbbe39ec42b100ae6d1d..df6dee4f79fcb74a6b83ec6237d21f3a607337e6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, 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
@@ -44,7 +44,6 @@ import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
@@ -141,8 +140,7 @@ public abstract class PrepareArguments extends Node {
                     ArgumentsAndSignature arguments = createArguments(call, varArgSignature, s3DefaultArguments);
                     entry = e = insert(new GenericCallEntry(varArgSignature, s3DefaultArguments, arguments));
                 }
-                VirtualFrame frame = SubstituteVirtualFrame.create(materializedFrame);
-                return executeArgs(e.arguments.matchedArguments, e.arguments.matchedSuppliedSignature, frame);
+                return executeArgs(e.arguments.matchedArguments, e.arguments.matchedSuppliedSignature, materializedFrame);
             }
         }
 
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 3c6ffeaa58399b08bf11b16a0cd183b45ebdf039..22a05aa10aebff3ee1cb23d2af99aa7a4aaf58da 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, 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
@@ -344,7 +344,7 @@ public final class RArguments {
 
     /**
      * An arguments array length of 1 is indicative of a substituted frame. See
-     * {@code SubstituteVirtualFrame}.
+     * {@code com.oracle.truffle.r.runtime.VirtualEvalFrame}.
      */
     public static Frame unwrap(Frame frame) {
         Object[] arguments = frame.getArguments();
@@ -353,8 +353,8 @@ public final class RArguments {
 
     /**
      * Checks {@code frame} corresponds to an R evaluation. Note that a
-     * {@code SubstituteVirtualFrame} will not return {@code true} to this call but it will if
-     * {@link #unwrap} is called first.
+     * {@code com.oracle.truffle.r.runtime.VirtualEvalFrame} will not return {@code true} to this
+     * call but it will if {@link #unwrap} is called first.
      */
     public static boolean isRFrame(Frame frame) {
         Object[] arguments = frame.getArguments();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/SubstituteVirtualFrame.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/SubstituteVirtualFrame.java
deleted file mode 100644
index 1acfb0d8743445e30f8e8138977251e3dda2a8c6..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/SubstituteVirtualFrame.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2013, 2016, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.runtime;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.frame.FrameDescriptor;
-import com.oracle.truffle.api.frame.FrameSlot;
-import com.oracle.truffle.api.frame.FrameSlotTypeException;
-import com.oracle.truffle.api.frame.MaterializedFrame;
-import com.oracle.truffle.api.frame.VirtualFrame;
-
-public abstract class SubstituteVirtualFrame implements VirtualFrame, MaterializedFrame {
-
-    /*
-     * These classes will specialize towards specific frame types, of which there are usually only
-     * one or two in the system. As a result, when we know the type of the substitute frame, we also
-     * know the type of the original frame.
-     */
-
-    private static final class Substitute1 extends SubstituteVirtualFrame {
-
-        @CompilationFinal private static Class<MaterializedFrame> frameClass;
-
-        protected Substitute1(MaterializedFrame originalFrame) {
-            super(originalFrame);
-        }
-
-        @Override
-        protected MaterializedFrame getOriginalFrame() {
-            return frameClass.cast(originalFrame);
-        }
-    }
-
-    private static final class Substitute2 extends SubstituteVirtualFrame {
-
-        @CompilationFinal private static Class<MaterializedFrame> frameClass;
-
-        protected Substitute2(MaterializedFrame originalFrame) {
-            super(originalFrame);
-        }
-
-        @Override
-        protected MaterializedFrame getOriginalFrame() {
-            return frameClass.cast(originalFrame);
-        }
-    }
-
-    private static final class SubstituteGeneric extends SubstituteVirtualFrame {
-
-        protected SubstituteGeneric(MaterializedFrame originalFrame) {
-            super(originalFrame);
-        }
-
-        @Override
-        protected MaterializedFrame getOriginalFrame() {
-            return originalFrame;
-        }
-    }
-
-    public static VirtualFrame create(MaterializedFrame frame) {
-        MaterializedFrame unwrappedFrame = frame instanceof SubstituteVirtualFrame ? ((SubstituteVirtualFrame) frame).getOriginalFrame() : frame;
-        @SuppressWarnings("unchecked")
-        Class<MaterializedFrame> clazz = (Class<MaterializedFrame>) unwrappedFrame.getClass();
-        if (Substitute1.frameClass == clazz) {
-            return new Substitute1(unwrappedFrame);
-        } else if (Substitute1.frameClass == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            Substitute1.frameClass = clazz;
-            return new Substitute1(unwrappedFrame);
-        } else if (Substitute2.frameClass == clazz) {
-            return new Substitute2(unwrappedFrame);
-        } else if (Substitute2.frameClass == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            Substitute2.frameClass = clazz;
-            return new Substitute2(unwrappedFrame);
-        } else {
-            return new SubstituteGeneric(unwrappedFrame);
-        }
-    }
-
-    protected final MaterializedFrame originalFrame;
-
-    protected SubstituteVirtualFrame(MaterializedFrame originalFrame) {
-        this.originalFrame = originalFrame;
-    }
-
-    protected abstract MaterializedFrame getOriginalFrame();
-
-    @Override
-    public FrameDescriptor getFrameDescriptor() {
-        return getOriginalFrame().getFrameDescriptor();
-    }
-
-    @Override
-    public Object[] getArguments() {
-        return getOriginalFrame().getArguments();
-    }
-
-    @Override
-    public MaterializedFrame materialize() {
-        return getOriginalFrame();
-    }
-
-    /*
-     * Delegates to #getOriginalFrame()
-     */
-
-    @Override
-    public Object getObject(FrameSlot slot) throws FrameSlotTypeException {
-        return getOriginalFrame().getObject(slot);
-    }
-
-    @Override
-    public void setObject(FrameSlot slot, Object value) {
-        getOriginalFrame().setObject(slot, value);
-    }
-
-    @Override
-    public byte getByte(FrameSlot slot) throws FrameSlotTypeException {
-        return getOriginalFrame().getByte(slot);
-    }
-
-    @Override
-    public void setByte(FrameSlot slot, byte value) {
-        getOriginalFrame().setByte(slot, value);
-    }
-
-    @Override
-    public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
-        return getOriginalFrame().getBoolean(slot);
-    }
-
-    @Override
-    public void setBoolean(FrameSlot slot, boolean value) {
-        getOriginalFrame().setBoolean(slot, value);
-    }
-
-    @Override
-    public int getInt(FrameSlot slot) throws FrameSlotTypeException {
-        return getOriginalFrame().getInt(slot);
-    }
-
-    @Override
-    public void setInt(FrameSlot slot, int value) {
-        getOriginalFrame().setInt(slot, value);
-    }
-
-    @Override
-    public long getLong(FrameSlot slot) throws FrameSlotTypeException {
-        return getOriginalFrame().getLong(slot);
-    }
-
-    @Override
-    public void setLong(FrameSlot slot, long value) {
-        getOriginalFrame().setLong(slot, value);
-    }
-
-    @Override
-    public float getFloat(FrameSlot slot) throws FrameSlotTypeException {
-        return getOriginalFrame().getFloat(slot);
-    }
-
-    @Override
-    public void setFloat(FrameSlot slot, float value) {
-        getOriginalFrame().setFloat(slot, value);
-    }
-
-    @Override
-    public double getDouble(FrameSlot slot) throws FrameSlotTypeException {
-        return getOriginalFrame().getDouble(slot);
-    }
-
-    @Override
-    public void setDouble(FrameSlot slot, double value) {
-        getOriginalFrame().setDouble(slot, value);
-    }
-
-    @Override
-    public Object getValue(FrameSlot slot) {
-        return getOriginalFrame().getValue(slot);
-    }
-
-    @Override
-    public boolean isObject(FrameSlot slot) {
-        return getOriginalFrame().isObject(slot);
-    }
-
-    @Override
-    public boolean isByte(FrameSlot slot) {
-        return getOriginalFrame().isByte(slot);
-    }
-
-    @Override
-    public boolean isBoolean(FrameSlot slot) {
-        return getOriginalFrame().isBoolean(slot);
-    }
-
-    @Override
-    public boolean isInt(FrameSlot slot) {
-        return getOriginalFrame().isInt(slot);
-    }
-
-    @Override
-    public boolean isLong(FrameSlot slot) {
-        return getOriginalFrame().isLong(slot);
-    }
-
-    @Override
-    public boolean isFloat(FrameSlot slot) {
-        return getOriginalFrame().isFloat(slot);
-    }
-
-    @Override
-    public boolean isDouble(FrameSlot slot) {
-        return getOriginalFrame().isDouble(slot);
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java
index bce8216199b597fadbd4e5d179aae6af19ca26e9..1b3503cce99681350554b94eb253903a92439bec 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java
@@ -26,35 +26,158 @@ import java.util.Arrays;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.FrameDescriptor;
+import com.oracle.truffle.api.frame.FrameSlot;
+import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.r.runtime.data.RFunction;
 
 /**
- * A "fake" {@link VirtualFrame}, to be used by {@code REngine}.eval only!
+ * A "fake" {@link VirtualFrame} that delegates everything to the wrapped frame except for the
+ * arguments array getter.
  */
-public abstract class VirtualEvalFrame extends SubstituteVirtualFrame implements VirtualFrame, MaterializedFrame {
+public abstract class VirtualEvalFrame implements MaterializedFrame {
 
     @CompilationFinal(dimensions = 1) protected final Object[] arguments;
+    final MaterializedFrame originalFrame;
 
     private VirtualEvalFrame(MaterializedFrame originalFrame, Object[] arguments) {
-        super(originalFrame);
         this.arguments = arguments;
+        this.originalFrame = originalFrame;
     }
 
-    @Override
     public abstract MaterializedFrame getOriginalFrame();
 
     @Override
-    public Object[] getArguments() {
+    public final FrameDescriptor getFrameDescriptor() {
+        return getOriginalFrame().getFrameDescriptor();
+    }
+
+    @Override
+    public final Object[] getArguments() {
         return arguments;
     }
 
     @Override
-    public MaterializedFrame materialize() {
+    public final MaterializedFrame materialize() {
         return this;
     }
 
+    /*
+     * Delegates to #getOriginalFrame()
+     */
+
+    @Override
+    public final Object getObject(FrameSlot slot) throws FrameSlotTypeException {
+        return getOriginalFrame().getObject(slot);
+    }
+
+    @Override
+    public final void setObject(FrameSlot slot, Object value) {
+        getOriginalFrame().setObject(slot, value);
+    }
+
+    @Override
+    public final byte getByte(FrameSlot slot) throws FrameSlotTypeException {
+        return getOriginalFrame().getByte(slot);
+    }
+
+    @Override
+    public final void setByte(FrameSlot slot, byte value) {
+        getOriginalFrame().setByte(slot, value);
+    }
+
+    @Override
+    public final boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
+        return getOriginalFrame().getBoolean(slot);
+    }
+
+    @Override
+    public final void setBoolean(FrameSlot slot, boolean value) {
+        getOriginalFrame().setBoolean(slot, value);
+    }
+
+    @Override
+    public final int getInt(FrameSlot slot) throws FrameSlotTypeException {
+        return getOriginalFrame().getInt(slot);
+    }
+
+    @Override
+    public final void setInt(FrameSlot slot, int value) {
+        getOriginalFrame().setInt(slot, value);
+    }
+
+    @Override
+    public final long getLong(FrameSlot slot) throws FrameSlotTypeException {
+        return getOriginalFrame().getLong(slot);
+    }
+
+    @Override
+    public final void setLong(FrameSlot slot, long value) {
+        getOriginalFrame().setLong(slot, value);
+    }
+
+    @Override
+    public final float getFloat(FrameSlot slot) throws FrameSlotTypeException {
+        return getOriginalFrame().getFloat(slot);
+    }
+
+    @Override
+    public final void setFloat(FrameSlot slot, float value) {
+        getOriginalFrame().setFloat(slot, value);
+    }
+
+    @Override
+    public final double getDouble(FrameSlot slot) throws FrameSlotTypeException {
+        return getOriginalFrame().getDouble(slot);
+    }
+
+    @Override
+    public final void setDouble(FrameSlot slot, double value) {
+        getOriginalFrame().setDouble(slot, value);
+    }
+
+    @Override
+    public final Object getValue(FrameSlot slot) {
+        return getOriginalFrame().getValue(slot);
+    }
+
+    @Override
+    public final boolean isObject(FrameSlot slot) {
+        return getOriginalFrame().isObject(slot);
+    }
+
+    @Override
+    public final boolean isByte(FrameSlot slot) {
+        return getOriginalFrame().isByte(slot);
+    }
+
+    @Override
+    public final boolean isBoolean(FrameSlot slot) {
+        return getOriginalFrame().isBoolean(slot);
+    }
+
+    @Override
+    public final boolean isInt(FrameSlot slot) {
+        return getOriginalFrame().isInt(slot);
+    }
+
+    @Override
+    public final boolean isLong(FrameSlot slot) {
+        return getOriginalFrame().isLong(slot);
+    }
+
+    @Override
+    public final boolean isFloat(FrameSlot slot) {
+        return getOriginalFrame().isFloat(slot);
+    }
+
+    @Override
+    public final boolean isDouble(FrameSlot slot) {
+        return getOriginalFrame().isDouble(slot);
+    }
+
     private static final class Substitute1 extends VirtualEvalFrame {
 
         @CompilationFinal private static Class<MaterializedFrame> frameClass;
@@ -105,7 +228,7 @@ public abstract class VirtualEvalFrame extends SubstituteVirtualFrame implements
         } else if (arguments[RArguments.INDEX_CALL] == null) {
             arguments[RArguments.INDEX_CALL] = RCaller.topLevel;
         }
-        MaterializedFrame unwrappedFrame = originalFrame instanceof SubstituteVirtualFrame ? ((SubstituteVirtualFrame) originalFrame).getOriginalFrame() : originalFrame;
+        MaterializedFrame unwrappedFrame = originalFrame instanceof VirtualEvalFrame ? ((VirtualEvalFrame) originalFrame).getOriginalFrame() : originalFrame;
         @SuppressWarnings("unchecked")
         Class<MaterializedFrame> clazz = (Class<MaterializedFrame>) unwrappedFrame.getClass();
         if (Substitute1.frameClass == clazz) {