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 e7884fbca072513057607385f5ef975128013bf7..51f811371e9c8bf5a3ffe2bc8f0cc7cc1a070403 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
@@ -38,6 +38,7 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.InlineCacheNode;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RError;
@@ -45,6 +46,7 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.VirtualEvalFrame;
 import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RPromise.EagerPromise;
+import com.oracle.truffle.r.runtime.data.RPromise.EagerPromiseBase;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseState;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
@@ -116,7 +118,7 @@ public class PromiseHelperNode extends RBaseNode {
         private boolean deoptimize(RPromise promise) {
             if (!promise.getState().isDefaultOpt()) {
                 deoptimizeProfile.enter();
-                EagerPromise eager = (EagerPromise) promise;
+                EagerPromiseBase eager = (EagerPromiseBase) promise;
                 return eager.deoptimize();
             }
 
@@ -156,7 +158,7 @@ public class PromiseHelperNode extends RBaseNode {
         if (state.isDefaultOpt()) {
             obj = generateValueDefault(frame, state, promise);
         } else {
-            obj = generateValueEager(frame, state, (EagerPromise) promise);
+            obj = generateValueEager(frame, state, (EagerPromiseBase) promise);
         }
         if (isEvaluated(promise)) {
             // TODO: this only happens if compilation is in play and, as such, is difficult to track
@@ -174,22 +176,23 @@ public class PromiseHelperNode extends RBaseNode {
             throw RError.error(RError.SHOW_CALLER, RError.Message.PROMISE_CYCLE);
         }
         try {
-            // Evaluate guarded by underEvaluation
-            promise.setState(PromiseState.UnderEvaluation);
-
             if (isInOriginFrame(frame, promise)) {
+                // state change must happen inside of conditional as isInOriginalFrame checks the
+                // state
+                promise.setState(PromiseState.UnderEvaluation);
                 if (expressionInlineCache == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    expressionInlineCache = insert(InlineCacheNode.createExpression(3));
+                    expressionInlineCache = insert(InlineCacheNode.createExpression(FastROptions.PromiseCacheSize.getNonNegativeIntValue()));
                 }
                 return expressionInlineCache.execute(frame, promise.getRep());
             } else {
+                promise.setState(PromiseState.UnderEvaluation);
                 Frame promiseFrame = promiseFrameProfile.profile(promise.getFrame());
                 assert promiseFrame != null;
 
                 if (promiseClosureCache == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    promiseClosureCache = insert(InlineCacheNode.createPromise(3));
+                    promiseClosureCache = insert(InlineCacheNode.createPromise(FastROptions.PromiseCacheSize.getNonNegativeIntValue()));
                 }
                 promiseFrame = wrapPromiseFrame(frame, promiseFrame);
                 return promiseClosureCache.execute(promiseFrame, promise.getClosure());
@@ -199,7 +202,7 @@ public class PromiseHelperNode extends RBaseNode {
         }
     }
 
-    private Object generateValueEager(VirtualFrame frame, PromiseState state, EagerPromise promise) {
+    private Object generateValueEager(VirtualFrame frame, PromiseState state, EagerPromiseBase promise) {
         assert state.isEager() || state == PromiseState.Promised;
         if (!isDeoptimized(promise)) {
             Assumption eagerAssumption = isValidAssumptionProfile.profile(promise.getIsValidAssumption());
@@ -209,7 +212,7 @@ public class PromiseHelperNode extends RBaseNode {
                     return checkNextNode().evaluate(frame, nextPromise);
                 } else {
                     assert state.isEager();
-                    return getEagerValue(frame, promise);
+                    return getEagerValue(frame, (EagerPromise) promise);
                 }
             } else {
                 CompilerDirectives.transferToInterpreter();
@@ -235,7 +238,7 @@ public class PromiseHelperNode extends RBaseNode {
             // Evaluate guarded by underEvaluation
             obj = generateValueDefaultSlowPath(frame, state, promise);
         } else {
-            obj = generateValueEagerSlowPath(frame, state, (EagerPromise) promise);
+            obj = generateValueEagerSlowPath(frame, state, (EagerPromiseBase) promise);
         }
         promise.setValue(obj);
         return obj;
@@ -268,7 +271,7 @@ public class PromiseHelperNode extends RBaseNode {
                         RCaller.createForPromise(RArguments.getCall(promiseFrame), frame == null ? 0 : RArguments.getDepth(frame)));
     }
 
-    private static Object generateValueEagerSlowPath(VirtualFrame frame, PromiseState state, EagerPromise promise) {
+    private static Object generateValueEagerSlowPath(VirtualFrame frame, PromiseState state, EagerPromiseBase promise) {
         assert state.isEager() || state == PromiseState.Promised;
         if (!promise.isDeoptimized()) {
             Assumption eagerAssumption = promise.getIsValidAssumption();
@@ -301,7 +304,7 @@ public class PromiseHelperNode extends RBaseNode {
      */
     public void materialize(RPromise promise) {
         if (isOptEagerProfile.profile(promise.getState().isEager()) || isOptPromisedProfile.profile(promise.getState() == PromiseState.Promised)) {
-            EagerPromise eager = (EagerPromise) promise;
+            EagerPromiseBase eager = (EagerPromiseBase) promise;
             eager.materialize();
         }
         // otherwise: already the generic and slow RPromise
@@ -319,7 +322,7 @@ public class PromiseHelperNode extends RBaseNode {
         return isNullFrameProfile.profile(promise.isNullFrame());
     }
 
-    private boolean isDeoptimized(EagerPromise promise) {
+    private boolean isDeoptimized(EagerPromiseBase promise) {
         return isDeoptimizedProfile.profile(promise.isDeoptimized());
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java
index a9757b9a83442c84f0ecf4f1df0cc0e3a52a367c..33b888daca886d672e7ee8a9f2bdcba23882ef95 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RMissingHelper.java
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.REmpty;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RPromise;
-import com.oracle.truffle.r.runtime.data.RPromise.EagerPromise;
+import com.oracle.truffle.r.runtime.data.RPromise.EagerPromiseBase;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseState;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 
@@ -158,8 +158,8 @@ public class RMissingHelper {
                 }
                 promise.setState(PromiseState.UnderEvaluation);
                 // TODO Profile necessary here???
-                if (promise instanceof EagerPromise) {
-                    EagerPromise eagerPromise = (EagerPromise) promise;
+                if (promise instanceof EagerPromiseBase) {
+                    EagerPromiseBase eagerPromise = (EagerPromiseBase) promise;
                     if (!eagerPromise.isDeoptimized()) {
                         Object eagerValue = eagerPromise.getEagerValue();
                         if (eagerValue instanceof RPromise) {
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 093c75a0a7bb3d22d77c450bedb03e80695fb3d6..911146cef4567a13f3ba111f4d933a9608fa392c 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
@@ -60,7 +60,8 @@ public enum FastROptions {
     EagerEvalConstants("Unconditionally evaluates constants before creating Promises", true),
     EagerEvalVariables("Enables optimistic eager evaluation of single variables reads", true),
     EagerEvalDefault("Enables optimistic eager evaluation of single variables reads (for default parameters)", false),
-    EagerEvalExpressions("Enables optimistic eager evaluation of trivial expressions", false);
+    EagerEvalExpressions("Enables optimistic eager evaluation of trivial expressions", false),
+    PromiseCacheSize("Enables inline caches for promises evaluation", "3", true);
 
     private final String help;
     private final boolean isBoolean;
@@ -101,6 +102,25 @@ public enum FastROptions {
         }
     }
 
+    public int getNonNegativeIntValue() {
+        assert !isBoolean;
+        if (value instanceof String) {
+            try {
+                int res = Integer.decode((String) value);
+                if (res >= 0) {
+                    return res;
+                } // else fall through to error message
+            } catch (NumberFormatException x) {
+                // fall through to error message
+            }
+        }
+
+        System.out.println("non negative integer option value expected with " + name());
+        System.exit(2);
+        return -1;
+
+    }
+
     private static FastROptions[] VALUES = values();
 
     static void setValue(String name, Object value) {
@@ -221,4 +241,9 @@ public enum FastROptions {
         }
         FastROptions.Debug.value = s;
     }
+
+    public static boolean noEagerEval() {
+        return !(EagerEval.getBooleanValue() || EagerEvalConstants.getBooleanValue() || EagerEvalVariables.getBooleanValue() || EagerEvalDefault.getBooleanValue() ||
+                        EagerEvalExpressions.getBooleanValue());
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java
index 9467d0ce824b3da920bc6bde7c290e721a0d26f8..02ba005555bb2e4552710e62c3c596f7fc780007 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/FastPathFactory.java
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.data;
 
 import java.util.function.Supplier;
 
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RBuiltin;
 import com.oracle.truffle.r.runtime.RVisibility;
 import com.oracle.truffle.r.runtime.nodes.RFastPathNode;
@@ -57,7 +58,7 @@ public interface FastPathFactory {
 
         @Override
         public boolean forcedEagerPromise(int index) {
-            return true;
+            return FastROptions.noEagerEval() ? false : true;
         }
     };
 
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 8431bfe89575a8551458ec0f2079a1367fece926..7d98b6e7bc2b2f4279d07b5f2258cddfc72ba727 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
@@ -33,7 +33,9 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RPerfStats;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
@@ -388,9 +390,19 @@ public final class RDataFactory {
 
     public static RPromise createEagerPromise(PromiseState state, Closure exprClosure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback,
                     int wrapIndex) {
+        if (FastROptions.noEagerEval()) {
+            throw RInternalError.shouldNotReachHere();
+        }
         return traceDataCreated(new RPromise.EagerPromise(state, exprClosure, eagerValue, notChangedNonLocally, targetFrame, feedback, wrapIndex));
     }
 
+    public static RPromise createPromisedPromise(Closure exprClosure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback) {
+        if (FastROptions.noEagerEval()) {
+            throw RInternalError.shouldNotReachHere();
+        }
+        return traceDataCreated(new RPromise.PromisedPromise(exprClosure, eagerValue, notChangedNonLocally, targetFrame, feedback));
+    }
+
     public static RPairList createPairList() {
         return traceDataCreated(new RPairList());
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
index 5bc8b35e360dd2ba827ba333db29c18bc339e97f..888c4ac622d9c3a1351c6113a2b3eaab5562571c 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
@@ -249,7 +249,7 @@ public class RPromise implements RTypedValue {
      * originally read from has not been altered in the mean time. If this cannot be guaranteed for
      * any reason, a Promise gets {@link #deoptimize()} (which includes {@link #materialize()}ion).
      */
-    public static final class EagerPromise extends RPromise {
+    public static class EagerPromiseBase extends RPromise {
         private final Object eagerValue;
 
         private final Assumption notChangedNonLocally;
@@ -263,7 +263,7 @@ public class RPromise implements RTypedValue {
          */
         private boolean deoptimized = false;
 
-        EagerPromise(PromiseState state, Closure closure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback, int wrapIndex) {
+        EagerPromiseBase(PromiseState state, Closure closure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback, int wrapIndex) {
             super(state, (MaterializedFrame) null, closure);
             assert state != PromiseState.Explicit;
             this.eagerValue = eagerValue;
@@ -320,6 +320,26 @@ public class RPromise implements RTypedValue {
         }
     }
 
+    /**
+     * This is a "proper" eager promise.
+     */
+    public static final class EagerPromise extends EagerPromiseBase {
+        EagerPromise(PromiseState state, Closure closure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback, int wrapIndex) {
+            super(state, closure, eagerValue, notChangedNonLocally, targetFrame, feedback, wrapIndex);
+        }
+    }
+
+    /**
+     * It's a variant of an eager promise used to store another promise, distinguished mostly for
+     * accounting purposes.
+     */
+    public static final class PromisedPromise extends EagerPromiseBase {
+
+        PromisedPromise(Closure closure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback) {
+            super(PromiseState.Promised, closure, eagerValue, notChangedNonLocally, targetFrame, feedback, -1);
+        }
+    }
+
     /**
      * Used to allow feedback on {@link EagerPromise} evaluation.
      */
@@ -377,7 +397,7 @@ public class RPromise implements RTypedValue {
 
         public RPromise createPromisedPromise(RPromise promisedPromise, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback) {
             assert state == PromiseState.Supplied;
-            return RDataFactory.createEagerPromise(PromiseState.Promised, exprClosure, promisedPromise, notChangedNonLocally, targetFrame, feedback, -1);
+            return RDataFactory.createPromisedPromise(exprClosure, promisedPromise, notChangedNonLocally, targetFrame, feedback);
         }
 
         public Object getExpr() {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsFastPath.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsFastPath.java
index 7784d35cb54a2a1b9c736a824a4764f8bbf04674..361c23ad89ca1f5d71a69fe7739f160e1e8c671a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsFastPath.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsFastPath.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.runtime.nodes;
 import java.util.Arrays;
 
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.data.FastPathFactory;
 
 final class EvaluatedArgumentsFastPath implements FastPathFactory {
@@ -47,7 +48,7 @@ final class EvaluatedArgumentsFastPath implements FastPathFactory {
 
     @Override
     public boolean forcedEagerPromise(int index) {
-        return forcedArguments[index];
+        return FastROptions.noEagerEval() ? false : forcedArguments[index];
     }
 
     public String toString(ArgumentsSignature signature) {
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
index 34515c506681fe427b49a650d40ce35c296a1139..eed0303cb578e4366c491fb19691957c725d6d73 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
@@ -46,7 +46,7 @@ import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.vm.EventConsumer;
 import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.api.vm.PolyglotEngine.Value;
-import com.oracle.truffle.r.runtime.data.RPromise.EagerPromise;
+import com.oracle.truffle.r.runtime.data.RPromise.EagerPromiseBase;
 
 public class FastRDebugTest {
     private Debugger debugger;
@@ -282,8 +282,8 @@ public class FastRDebugTest {
 
     Object getRValue(Object value) {
         // This will only work in simple cases
-        if (value instanceof EagerPromise) {
-            return ((EagerPromise) value).getValue();
+        if (value instanceof EagerPromiseBase) {
+            return ((EagerPromiseBase) value).getValue();
         }
         return value;
     }