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 5a101e6fdb9b732c4b04290468ad6523d956c214..a26281bc3111e1881a84dd7064563cbc3209d5e8 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
@@ -44,6 +44,7 @@ import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.RContext.ConsoleHandler;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 import com.oracle.truffle.r.runtime.env.*;
 import com.oracle.truffle.r.runtime.env.REnvironment.PutException;
 import com.oracle.truffle.r.runtime.ffi.*;
@@ -427,8 +428,6 @@ public final class REngine implements RContext.Engine {
         return result;
     }
 
-    private static boolean traceMakeCallTarget;
-
     /**
      * Wraps the Truffle AST in {@code node} in an anonymous function and returns a
      * {@link RootCallTarget} for it. We define the
@@ -454,32 +453,12 @@ public final class REngine implements RContext.Engine {
      */
     @SlowPath
     private static RootCallTarget doMakeCallTarget(RNode body, String funName) {
-        if (traceMakeCallTarget) {
-            doTraceMakeCallTarget(body);
-        }
         REnvironment.FunctionDefinition rootNodeEnvironment = new REnvironment.FunctionDefinition(REnvironment.emptyEnv());
         FunctionDefinitionNode rootNode = new FunctionDefinitionNode(null, rootNodeEnvironment, body, FormalArguments.NO_ARGS, funName, true, true);
         RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
         return callTarget;
     }
 
-    private static void doTraceMakeCallTarget(RNode body) {
-        String nodeClassName = body.getClass().getSimpleName();
-        SourceSection ss = body.getSourceSection();
-        String trace;
-        if (ss == null) {
-            if (body instanceof ConstantNode) {
-                trace = ((ConstantNode) body).getValue().toString();
-            } else {
-                trace = "not constant/no source";
-            }
-        } else {
-            trace = ss.toString();
-        }
-        RContext.getInstance().getConsoleHandler().printf("makeCallTarget: node: %s, %s%n", nodeClassName, trace);
-
-    }
-
     /**
      * Execute {@code callTarget} in {@code frame}, optionally printing any result. N.B.
      * {@code callTarget.call} will create a new {@link VirtualFrame} called, say, {@code newFrame},
@@ -513,11 +492,13 @@ public final class REngine implements RContext.Engine {
         return result;
     }
 
+    private static final PromiseProfile globalPromiseProfile = new PromiseProfile();
+
     @SlowPath
     private static void printResult(Object result) {
         if (RContext.isVisible()) {
             // TODO cache this
-            Object resultValue = RPromise.checkEvaluate(null, result);
+            Object resultValue = RPromise.checkEvaluate(null, result, globalPromiseProfile);
             RFunction function = (RFunction) REnvironment.baseEnv().get("print");
             function.getTarget().call(RArguments.create(function, null, new Object[]{resultValue, RMissing.instance}));
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
index 12577371ac97a73c7036aa0f0ed059c3f8ae801f..2afa5567910fcc655244c33a4f46d53ea5965eb3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
@@ -33,6 +33,7 @@ import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 import com.oracle.truffle.r.runtime.data.model.*;
 import com.oracle.truffle.r.runtime.env.*;
 
@@ -42,6 +43,8 @@ public abstract class DoCall extends RBuiltinNode {
     @Child private IndirectCallNode funCall = Truffle.getRuntime().createIndirectCallNode();
     @Child private Get getNode;
 
+    private final PromiseProfile promiseProfile = new PromiseProfile();
+
     @Specialization(guards = "lengthOne")
     protected Object doDoCall(VirtualFrame frame, RAbstractStringVector fname, RList argsAsList, @SuppressWarnings("unused") REnvironment env) {
         RFunction func = RContext.getEngine().lookupBuiltin(fname.getDataAt(0));
@@ -56,7 +59,7 @@ public abstract class DoCall extends RBuiltinNode {
         Object n = argsAsList.getNames();
         String[] argNames = n == RNull.instance ? null : ((RStringVector) n).getDataNonShared();
         EvaluatedArguments evaledArgs = EvaluatedArguments.create(argValues, argNames);
-        EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(frame, func, evaledArgs, getEncapsulatingSourceSection());
+        EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(frame, func, evaledArgs, getEncapsulatingSourceSection(), promiseProfile);
         Object[] callArgs = RArguments.create(func, funCall.getSourceSection(), reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames());
         return funCall.call(frame, func.getTarget(), callArgs);
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Force.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Force.java
index 1f0079d04a44f69ae5d6d52d2dde6a34f223ebe7..a0d5e615c8a1bf6fe85f2b1f0db1521b0727b309 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Force.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Force.java
@@ -30,16 +30,19 @@ import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 
 @RBuiltin(name = "force", kind = SUBSTITUTE, parameterNames = {"x"})
 // TODO revert to R (promises)
 public abstract class Force extends RBuiltinNode {
 
+    private final PromiseProfile promiseProfile = new PromiseProfile();
+
     @Specialization
     protected Object force(VirtualFrame frame, Object arg) {
         if (arg instanceof RPromise) {
             RPromise promise = (RPromise) arg;
-            if (promise.isEvaluated()) {
+            if (promise.isEvaluated(promiseProfile)) {
                 return promise.getValue();
             } else {
                 SourceSection callSrc = RArguments.getCallSourceSection(frame);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
index c47ada011af6093e43895b5587e17d7318b25653..2f4c7d542d9a5a2c186edf50127c0cf2cf607359 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Missing.java
@@ -32,10 +32,13 @@ import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 
 @RBuiltin(name = "missing", kind = PRIMITIVE, parameterNames = {"x"}, nonEvalArgs = {0})
 public abstract class Missing extends RBuiltinNode {
 
+    private final PromiseProfile promiseProfile = new PromiseProfile();
+
     @Specialization
     protected byte missing(VirtualFrame frame, RPromise promise) {
         controlVisibility();
@@ -54,13 +57,13 @@ public abstract class Missing extends RBuiltinNode {
             return RRuntime.asLogical(false);
         }
 
-        return RRuntime.asLogical(RMissingHelper.isMissing(obj));
+        return RRuntime.asLogical(RMissingHelper.isMissing(obj, promiseProfile));
     }
 
     @Specialization(guards = "!isPromise")
     protected byte missing(Object obj) {
         controlVisibility();
-        return RRuntime.asLogical(RMissingHelper.isMissing(obj));
+        return RRuntime.asLogical(RMissingHelper.isMissing(obj, promiseProfile));
     }
 
     public boolean isPromise(Object obj) {
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 8dd8ca1aeb9f32f837d2789e68373a92627e1e9f..20b5681ace7487e18a22d2a1ea854a2d44f7cbba 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
@@ -35,6 +35,7 @@ import com.oracle.truffle.r.nodes.access.FrameSlotNode.InternalFrameSlot;
 import com.oracle.truffle.r.nodes.builtin.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 import com.oracle.truffle.r.runtime.ops.na.*;
 
 /**
@@ -52,6 +53,8 @@ public abstract class OnExit extends RInvisibleBuiltinNode {
     private final ConditionProfile emptyPromiseProfile = ConditionProfile.createBinaryProfile();
     private final NAProfile na = NAProfile.create();
 
+    private final PromiseProfile promiseProfile = new PromiseProfile();
+
     @Override
     public RNode[] getParameterValues() {
         return new RNode[]{ConstantNode.create(RNull.instance), ConstantNode.create(false)};
@@ -66,10 +69,10 @@ public abstract class OnExit extends RInvisibleBuiltinNode {
         }
 
         // the empty (RNull.instance) expression is used to clear on.exit
-        boolean empty = emptyPromiseProfile.profile(expr.isDefaulted());
+        boolean empty = emptyPromiseProfile.profile(expr.isDefault(promiseProfile));
 
         assert !empty || expr.getRep() instanceof ConstantNode : "only ConstantNode expected for defaulted promise";
-        assert empty || !expr.isEvaluated() : "promise cannot already be evaluated";
+        assert empty || !expr.isEvaluated(promiseProfile) : "promise cannot already be evaluated";
 
         ArrayList<Object> current;
         FrameSlot slot = onExitSlot.executeFrameSlot(frame);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TryFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TryFunctions.java
index 80272716af56a0c1e857f876ee5bcd3b92dc999d..4bc79b72ac0a5ff84f146599adc898f24f0bde0e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TryFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TryFunctions.java
@@ -31,6 +31,7 @@ import com.oracle.truffle.r.nodes.expressions.*;
 import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 
 /**
  * Temporary substitutions that just evaluate the expression for package loading and assume no
@@ -42,6 +43,8 @@ public class TryFunctions {
 
         @Child private ExpressionExecutorNode exprExecNode = ExpressionExecutorNode.create();
 
+        private final PromiseProfile promiseProfile = new PromiseProfile();
+
         @Override
         public RNode[] getParameterValues() {
             return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(RRuntime.LOGICAL_FALSE)};
@@ -50,7 +53,7 @@ public class TryFunctions {
         @Specialization
         protected Object doTry(VirtualFrame frame, RPromise expr, @SuppressWarnings("unused") byte silent) {
             controlVisibility();
-            return PromiseHelper.evaluate(frame, exprExecNode, expr);
+            return PromiseHelper.evaluate(frame, exprExecNode, expr, promiseProfile);
         }
     }
 
@@ -60,6 +63,8 @@ public class TryFunctions {
 
         @Child private ExpressionExecutorNode exprExecNode = ExpressionExecutorNode.create();
 
+        private final PromiseProfile promiseProfile = new PromiseProfile();
+
         @Override
         public RNode[] getParameterValues() {
             return new RNode[]{ConstantNode.create(RMissing.instance), ConstantNode.create(EMPTY_OBJECT_ARRAY)};
@@ -74,7 +79,7 @@ public class TryFunctions {
         @Specialization
         protected Object doTryCatch(VirtualFrame frame, RPromise expr, Object[] args) {
             controlVisibility();
-            return PromiseHelper.evaluate(frame, exprExecNode, expr);
+            return PromiseHelper.evaluate(frame, exprExecNode, expr, promiseProfile);
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java
index ea8de547b96b899e5f470184884dc308a8576495..dc2afb7fbf7a5cce07af04b5024a4947ccebcc3e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UseMethod.java
@@ -22,6 +22,7 @@ import com.oracle.truffle.r.nodes.control.*;
 import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 
 @RBuiltin(name = "UseMethod", kind = PRIMITIVE, parameterNames = {"generic", "object"})
 public abstract class UseMethod extends RBuiltinNode {
@@ -54,6 +55,8 @@ public abstract class UseMethod extends RBuiltinNode {
         @Child protected ClassHierarchyNode classHierarchyNode = ClassHierarchyNodeFactory.create(null);
         protected final String[] suppliedArgsNames;
 
+        private final PromiseProfile promiseProfile = new PromiseProfile();
+
         public UseMethodNode(String[] suppliedArgsNames) {
             this.suppliedArgsNames = suppliedArgsNames;
         }
@@ -79,7 +82,7 @@ public abstract class UseMethod extends RBuiltinNode {
                 enclosingArg = varArgs.getValues()[0];
             }
 
-            enclosingArg = RPromise.checkEvaluate(frame, enclosingArg);
+            enclosingArg = RPromise.checkEvaluate(frame, enclosingArg, promiseProfile);
             return enclosingArg;
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSetField.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSetField.java
deleted file mode 100644
index d37fc8b273845bde73d7876f10fe6b9496f4b092..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSetField.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2014, 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.nodes.builtin.fastr;
-
-import java.lang.reflect.*;
-
-import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.r.nodes.builtin.*;
-import com.oracle.truffle.r.runtime.*;
-import com.oracle.truffle.r.runtime.RError.Message;
-import com.oracle.truffle.r.runtime.data.*;
-import com.oracle.truffle.r.runtime.data.model.*;
-
-@RBuiltin(name = "fastr.setfield", kind = RBuiltinKind.PRIMITIVE, parameterNames = {"field", "value"})
-public abstract class FastRSetField extends RInvisibleBuiltinNode {
-
-    @Specialization
-    protected RNull setField(RAbstractStringVector vec, Object value) {
-        controlVisibility();
-        String qualFieldName = vec.getDataAt(0);
-        int lx = qualFieldName.lastIndexOf('.');
-        String simpleName = qualFieldName.substring(lx + 1);
-        String className = qualFieldName.substring(0, lx);
-        if (!className.startsWith("com")) {
-            className = "com.oracle.truffle.r." + className;
-        }
-        try {
-            Class<?> klass = Class.forName(className);
-            Field field = klass.getDeclaredField(simpleName);
-            field.setAccessible(true);
-            Class<?> fieldType = field.getType();
-            switch (fieldType.getSimpleName()) {
-                case "boolean":
-                    if (value instanceof Byte) {
-                        field.setBoolean(null, RRuntime.fromLogical((byte) value));
-                    } else {
-                        error(qualFieldName);
-                    }
-            }
-        } catch (Exception ex) {
-            throw RError.error(Message.GENERIC, ex.getMessage());
-        }
-        return RNull.instance;
-    }
-
-    private static void error(String fieldName) throws RError {
-        throw RError.error(Message.GENERIC, "value is wrong type for %s", fieldName);
-    }
-
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
index 86abf3a2635c2d40742801560ff628be2d09c6ed..a329deb1ce0fb75b9834e8783d35f84e4cf61145 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
@@ -31,8 +31,7 @@ import com.oracle.truffle.r.nodes.expressions.*;
 import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
-import com.oracle.truffle.r.runtime.data.RPromise.EvalPolicy;
-import com.oracle.truffle.r.runtime.data.RPromise.PromiseType;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 import com.oracle.truffle.r.runtime.env.*;
 
 /**
@@ -73,6 +72,7 @@ public abstract class AccessArgumentNode extends RNode {
 
     private final BranchProfile needsCalleeFrame = new BranchProfile();
     private final BranchProfile strictEvaluation = new BranchProfile();
+    private final PromiseProfile promiseProfile = new PromiseProfile();
 
     /**
      * @param index {@link #getIndex()}
@@ -114,23 +114,24 @@ public abstract class AccessArgumentNode extends RNode {
     }
 
     private Object handlePromise(VirtualFrame frame, RPromise promise, EnvProvider envProvider, boolean useExprExecNode) {
-        assert promise.getType() != PromiseType.NO_ARG;
+        assert !promise.isNonArgument();
+        CompilerAsserts.compilationConstant(useExprExecNode);
 
         // Check whether it is necessary to create a callee REnvironment for the promise
-        if (promise.needsCalleeFrame()) {
+        if (promise.needsCalleeFrame(promiseProfile)) {
             needsCalleeFrame.enter();
             // In this case the promise might lack the proper REnvironment, as it was created before
             // the environment was
-            promise.updateEnv(envProvider.getREnvironmentFor(frame));
+            promise.updateEnv(envProvider.getREnvironmentFor(frame), promiseProfile);
         }
 
         // Now force evaluation for INLINED (might be the case for arguments by S3MethodDispatch)
-        if (promise.getEvalPolicy() == EvalPolicy.INLINED) {
-            if (CompilerAsserts.compilationConstant(useExprExecNode)) {
-                return PromiseHelper.evaluate(frame, exprExecNode, promise);
+        if (promise.isInlined(promiseProfile)) {
+            if (useExprExecNode) {
+                return PromiseHelper.evaluate(frame, exprExecNode, promise, promiseProfile);
             } else {
                 strictEvaluation.enter();
-                return promise.evaluate(frame);
+                return promise.evaluate(frame, promiseProfile);
             }
         }
         return promise;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
index 17b0c0a81c51669f085d03c754f05cc844b29975..70f5564b368bc8dc95ce0f082be9d6c5905474fc 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariableNode.java
@@ -30,7 +30,6 @@ import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.ReadVariableNodeFactory.BuiltinFunctionVariableNodeFactory;
 import com.oracle.truffle.r.nodes.access.ReadVariableNodeFactory.ReadAndCopySuperVariableNodeFactory;
@@ -42,10 +41,13 @@ import com.oracle.truffle.r.nodes.expressions.*;
 import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 import com.oracle.truffle.r.runtime.data.model.*;
 
 public abstract class ReadVariableNode extends RNode implements VisibilityController {
 
+    protected final PromiseProfile promiseProfile = new PromiseProfile();
+
     public abstract Object execute(VirtualFrame frame, MaterializedFrame enclosingFrame);
 
     /**
@@ -152,13 +154,13 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
         }
         if (obj instanceof RPromise) {
             RPromise promise = (RPromise) obj;
-            if (!promise.isEvaluated()) {
+            if (!promise.isEvaluated(promiseProfile)) {
                 if (!forcePromise) {
                     // since we do not know what type the evaluates to, it may match.
                     // we recover from a wrong type later
                     return true;
                 } else {
-                    obj = promise.evaluate(frame);
+                    obj = promise.evaluate(frame, promiseProfile);
                 }
             } else {
                 obj = promise.getValue();
@@ -189,16 +191,12 @@ public abstract class ReadVariableNode extends RNode implements VisibilityContro
 
         @Child private ExpressionExecutorNode exprExecNode = ExpressionExecutorNode.create();
 
-        private final BranchProfile directlyEvaluatedProfile = new BranchProfile();
-
         @Specialization
         public Object doValue(VirtualFrame frame, RPromise promise) {
-            if (!promise.isEvaluated() && promise.isInOriginFrame(frame)) {
-                directlyEvaluatedProfile.enter();
-
-                return PromiseHelper.evaluate(frame, exprExecNode, promise);
+            if (!promise.isEvaluated(promiseProfile) && promise.isInOriginFrame(frame, promiseProfile)) {
+                return PromiseHelper.evaluate(frame, exprExecNode, promise, promiseProfile);
             }
-            return promise.evaluate(frame);
+            return promise.evaluate(frame, promiseProfile);
         }
 
         @Specialization
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java
index bda792a0fdc575037f181d10916a11acae081dec..8a5296ec23edec3a0cccff747f0238fc3512111f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.r.nodes.expressions.*;
 import com.oracle.truffle.r.nodes.function.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 
 /**
  * An {@link RNode} that handles accesses to components of the variadic argument (..1, ..2, etc.).
@@ -39,6 +40,8 @@ public class ReadVariadicComponentNode extends RNode {
 
     private final int index;
 
+    private final PromiseProfile promiseProfile = new PromiseProfile();
+
     public ReadVariadicComponentNode(int index) {
         this.index = index;
     }
@@ -64,7 +67,7 @@ public class ReadVariadicComponentNode extends RNode {
         if (ret instanceof RPromise) {
             // This might be the case, as lookup only checks for "..." to be a promise and forces it
             // eventually, NOT (all) of its content
-            ret = PromiseHelper.evaluate(frame, exprExecNode, (RPromise) ret);
+            ret = PromiseHelper.evaluate(frame, exprExecNode, (RPromise) ret, promiseProfile);
         }
         return ret == null ? RMissing.instance : ret;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
index 228fa37233c3afe4403cdda9f361404df00525ab..cb1486f4e4b210c8613102773b773b5274e67ad0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java
@@ -36,6 +36,7 @@ import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RPromise.EvalPolicy;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseType;
 import com.oracle.truffle.r.runtime.data.RPromise.RPromiseFactory;
 
@@ -46,8 +47,8 @@ import com.oracle.truffle.r.runtime.data.RPromise.RPromiseFactory;
  * {@link #matchArguments(VirtualFrame, RFunction, UnmatchedArguments, SourceSection, SourceSection)}
  * . The other match functions are used for special cases, where builtins make it necessary to
  * re-match parameters, e.g.:
- * {@link #matchArgumentsEvaluated(VirtualFrame, RFunction, EvaluatedArguments, SourceSection)} for
- * 'UseMethod' and
+ * {@link #matchArgumentsEvaluated(VirtualFrame, RFunction, EvaluatedArguments, SourceSection, PromiseProfile)}
+ * for 'UseMethod' and
  * {@link #matchArgumentsInlined(VirtualFrame, RFunction, UnmatchedArguments, SourceSection, SourceSection)}
  * for builtins which are implemented in Java ( @see {@link RBuiltinNode#inline(InlinedArguments)}
  * </p>
@@ -186,7 +187,7 @@ public class ArgumentMatcher {
      * @return A Fresh {@link EvaluatedArguments} containing the arguments rearranged and stuffed
      *         with default values (in the form of {@link RPromise}s where needed)
      */
-    public static EvaluatedArguments matchArgumentsEvaluated(VirtualFrame frame, RFunction function, EvaluatedArguments evaluatedArgs, SourceSection callSrc) {
+    public static EvaluatedArguments matchArgumentsEvaluated(VirtualFrame frame, RFunction function, EvaluatedArguments evaluatedArgs, SourceSection callSrc, PromiseProfile promiseProfile) {
         RRootNode rootNode = (RRootNode) function.getTarget().getRootNode();
         FormalArguments formals = rootNode.getFormalArguments();
         Object[] evaledArgs = permuteArguments(function, evaluatedArgs.getEvaluatedArgs(), evaluatedArgs.getNames(), formals, new VarArgsAsObjectArrayFactory(), new ObjectArrayFactory(), callSrc,
@@ -211,7 +212,7 @@ public class ArgumentMatcher {
                 }
             } else if (function.isBuiltin() && evaledArg instanceof RPromise) {
                 RPromise promise = (RPromise) evaledArg;
-                evaledArgs[i] = promise.evaluate(frame);
+                evaledArgs[i] = promise.evaluate(frame, promiseProfile);
             }
         }
         return new EvaluatedArguments(evaledArgs, formals.getNames());
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java
index c81a8a215c4aea86fd3102ebca1ab36ad192c8dc..f3f1a671d2ed92b3214ef8cedf58f43c8be2bb0e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java
@@ -22,6 +22,7 @@ import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 import com.oracle.truffle.r.runtime.data.model.*;
 
 import edu.umd.cs.findbugs.annotations.*;
@@ -177,6 +178,8 @@ public class GroupDispatchNode extends S3DispatchNode {
         return null;
     }
 
+    private final PromiseProfile promiseProfile = new PromiseProfile();
+
     @SlowPath
     private void initFunCall(VirtualFrame frame, RFunction func) {
         // avoid re-evaluating arguments.
@@ -189,11 +192,11 @@ public class GroupDispatchNode extends S3DispatchNode {
                     if (evaluatedArgs[i] instanceof RArgsValuesAndNames) {
                         RArgsValuesAndNames argsValuesAndNames = (RArgsValuesAndNames) evaluatedArgs[i];
                         if (argsValuesAndNames.length() == 1) {
-                            argArray[index++] = ConstantNode.create(RPromise.checkEvaluate(frame, argsValuesAndNames.getValues()[0]));
+                            argArray[index++] = ConstantNode.create(RPromise.checkEvaluate(frame, argsValuesAndNames.getValues()[0], promiseProfile));
                         } else {
                             argArray = new RNode[argArray.length + argsValuesAndNames.length() - 1];
                             for (int j = 0; j < argsValuesAndNames.length(); j++) {
-                                argArray[index++] = ConstantNode.create(RPromise.checkEvaluate(frame, argsValuesAndNames.getValues()[j]));
+                                argArray[index++] = ConstantNode.create(RPromise.checkEvaluate(frame, argsValuesAndNames.getValues()[j], promiseProfile));
                             }
                         }
                     } else {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelper.java
index 0054c1651f96ae2a5549fbab9494e6255d036315..0fa19b65e870eaec0aad4d040896c2ee867693ff 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelper.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelper.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.expressions.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 
 /**
  * Holds {@link RPromise}-related functionality that cannot be implemented in
@@ -35,17 +36,18 @@ import com.oracle.truffle.r.runtime.data.*;
  */
 public class PromiseHelper {
     /**
-     * Guarded by {@link RPromise#isInOriginFrame(VirtualFrame)}.
+     * Guarded by {@link RPromise#isInOriginFrame(VirtualFrame,PromiseProfile)}.
      *
      * @param frame The current {@link VirtualFrame}
      * @param exprExecNode The {@link ExpressionExecutorNode}
      * @param promise The {@link RPromise} to evaluate
+     * @param profile the profile for the site that operates on the promise
      * @return Evaluates the given {@link RPromise} in the given frame using the
      *         {@link ExpressionExecutorNode}
      */
-    public static Object evaluate(VirtualFrame frame, ExpressionExecutorNode exprExecNode, RPromise promise) {
-        if (promise.isEvaluated() || !promise.isInOriginFrame(frame)) {
-            return promise.evaluate(frame);
+    public static Object evaluate(VirtualFrame frame, ExpressionExecutorNode exprExecNode, RPromise promise, PromiseProfile profile) {
+        if (promise.isEvaluated(profile) || !promise.isInOriginFrame(frame, profile)) {
+            return promise.evaluate(frame, profile);
         }
 
         // Check for dependency cycle
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java
index 3bd056722a7160bf4771f6b565a626922614cb9b..84b9afed9766fb4ad8a67503347ac3e6307eb02a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
 import com.oracle.truffle.r.runtime.data.RPromise.Closure;
 import com.oracle.truffle.r.runtime.data.RPromise.EvalPolicy;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 import com.oracle.truffle.r.runtime.data.RPromise.PromiseType;
 import com.oracle.truffle.r.runtime.data.RPromise.RPromiseFactory;
 import com.oracle.truffle.r.runtime.env.*;
@@ -57,6 +58,8 @@ public class PromiseNode extends RNode {
      */
     protected final EnvProvider envProvider;
 
+    protected final PromiseProfile promiseProfile = new PromiseProfile();
+
     /**
      * @param factory {@link #factory}
      * @param envProvider {@link #envProvider}
@@ -142,11 +145,11 @@ public class PromiseNode extends RNode {
                     return RMissing.instance;
                 }
                 RPromise promise = factory.createPromiseDefault();
-                return PromiseHelper.evaluate(frame, exprExecNode, promise);
+                return PromiseHelper.evaluate(frame, exprExecNode, promise, promiseProfile);
             } else if (obj instanceof RArgsValuesAndNames) {
-                return ((RArgsValuesAndNames) obj).evaluate(frame);
+                return ((RArgsValuesAndNames) obj).evaluate(frame, promiseProfile);
             } else {
-                return RPromise.checkEvaluate(frame, obj);
+                return RPromise.checkEvaluate(frame, obj, promiseProfile);
             }
         }
     }
@@ -182,6 +185,8 @@ public class PromiseNode extends RNode {
         private final RPromise promise;
         @CompilationFinal private boolean isEvaluated = false;
 
+        private final PromiseProfile promiseProfile = new PromiseProfile();
+
         private VarArgPromiseNode(RPromise promise) {
             this.promise = promise;
         }
@@ -192,8 +197,8 @@ public class PromiseNode extends RNode {
             // the correct frame anyway
             if (!isEvaluated) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                Object result = promise.evaluate(frame);
-                isEvaluated = promise.isEvaluated();
+                Object result = promise.evaluate(frame, promiseProfile);
+                isEvaluated = promise.isEvaluated(promiseProfile);
                 return result;
             }
 
@@ -273,6 +278,8 @@ public class PromiseNode extends RNode {
         @Children private final RNode[] varargs;
         protected final String[] names;
 
+        private final PromiseProfile promiseProfile = new PromiseProfile();
+
         public InlineVarArgsPromiseNode(RNode[] nodes, String[] names) {
             this.varargs = nodes;
             this.names = names;
@@ -302,12 +309,12 @@ public class PromiseNode extends RNode {
                     evaluatedNames = Utils.resizeArray(evaluatedNames, newLength);
                     Object[] varargValues = argsValuesAndNames.getValues();
                     for (int j = 0; j < argsValuesAndNames.length(); j++) {
-                        evaluatedArgs[index] = RPromise.checkEvaluate(frame, varargValues[j]);
+                        evaluatedArgs[index] = RPromise.checkEvaluate(frame, varargValues[j], promiseProfile);
                         evaluatedNames[index] = argsValuesAndNames.getNames()[j];
                         index++;
                     }
                 } else {
-                    evaluatedArgs[index++] = RPromise.checkEvaluate(frame, argValue);
+                    evaluatedArgs[index++] = RPromise.checkEvaluate(frame, argValue, promiseProfile);
                 }
             }
             return new RArgsValuesAndNames(evaluatedArgs, evaluatedNames);
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 e81cf4bb82beb67f8a0c62fbffffff5458bb6ede..8bce1f373c46f5c3f91c065c1a8690749eae4a34 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
@@ -27,6 +27,7 @@ import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.r.nodes.*;
 import com.oracle.truffle.r.nodes.access.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 
 /**
  * This class implements the behavior for {@link RMissing} which is needed inside this module, as it
@@ -43,7 +44,7 @@ public class RMissingHelper {
      * @param value The value that should be examined
      * @return <code>true</code> iff this value is 'missing' in the definition of R
      */
-    public static boolean isMissing(Object value) {
+    public static boolean isMissing(Object value, PromiseProfile promiseProfile) {
         if (value == RMissing.instance) {
             return true;
         }
@@ -51,7 +52,7 @@ public class RMissingHelper {
         // This might be a promise...
         if (value instanceof RPromise) {
             RPromise promise = (RPromise) value;
-            if (promise.isDefaulted() || isMissingSymbol(promise)) {
+            if (promise.isDefault(promiseProfile) || isMissingSymbol(promise)) {
                 return true;
             }
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java
index 9b2521f596272fc440cd6949e78b197c7e871157..afdc7cdbcdd58790ce6dd1edc841de6522092707 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodDispatchNode.java
@@ -19,9 +19,12 @@ import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.data.*;
+import com.oracle.truffle.r.runtime.data.RPromise.*;
 
 public class UseMethodDispatchNode extends S3DispatchNode {
 
+    private final PromiseProfile promiseProfile = new PromiseProfile();
+
     UseMethodDispatchNode(final String generic, final RStringVector type) {
         this.genericName = generic;
         this.type = type;
@@ -108,7 +111,7 @@ public class UseMethodDispatchNode extends S3DispatchNode {
         // ...and use them as 'supplied' arguments...
         EvaluatedArguments evaledArgs = EvaluatedArguments.create(argValues, argNames);
         // ...to match them against the chosen function's formal arguments
-        EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(frame, targetFunction, evaledArgs, getEncapsulatingSourceSection());
+        EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(frame, targetFunction, evaledArgs, getEncapsulatingSourceSection(), promiseProfile);
         return executeHelper2(callerFrame, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames());
     }
 
@@ -137,7 +140,7 @@ public class UseMethodDispatchNode extends S3DispatchNode {
         // ...and use them as 'supplied' arguments...
         EvaluatedArguments evaledArgs = EvaluatedArguments.create(argValues, null);
         // ...to match them against the chosen function's formal arguments
-        EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(callerFrame, targetFunction, evaledArgs, getEncapsulatingSourceSection());
+        EvaluatedArguments reorderedArgs = ArgumentMatcher.matchArgumentsEvaluated(callerFrame, targetFunction, evaledArgs, getEncapsulatingSourceSection(), promiseProfile);
         return executeHelper2(callerFrame, reorderedArgs.getEvaluatedArgs(), reorderedArgs.getNames());
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
index 1b6402cc82e76b843b2cfd3e88e236c08d091d92..8326f1810e8d826ea75453c4561f6f0c10d9b29e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
@@ -83,12 +83,21 @@ public class REnvVars {
         }
     }
 
+    private static String rHome;
+
     public static String rHome() {
         // This can be called before initialize, "R RHOME"
-        String rHome = getEnvVars().get("R_HOME");
         if (rHome == null) {
-            // Should only happen in a unit test run
-            rHome = System.getProperty("user.dir");
+            rHome = getEnvVars().get("R_HOME");
+            if (rHome == null) {
+                // Should only happen in a unit test run, but can differ whether
+                // run from within IDE or from command line.
+                File file = new File(System.getProperty("user.dir"));
+                if (file.getName().endsWith("r.test")) {
+                    file = file.getParentFile();
+                }
+                rHome = file.getAbsolutePath();
+            }
         }
         return rHome;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java
index f18091e63800e28c6f79fb5ed518fb3e7554f6b5..7789ec888fa3f094d084139deceae8193134b20a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RArgsValuesAndNames.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.runtime.data;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.r.runtime.data.RPromise.PromiseProfile;
 
 /**
  * A simple wrapper class for passing the ... argument through RArguments
@@ -49,10 +50,10 @@ public class RArgsValuesAndNames {
         }
     }
 
-    public RArgsValuesAndNames evaluate(VirtualFrame frame) {
+    public RArgsValuesAndNames evaluate(VirtualFrame frame, PromiseProfile promiseProfile) {
         Object[] newValues = new Object[values.length];
         for (int i = 0; i < values.length; i++) {
-            newValues[i] = RPromise.checkEvaluate(frame, values[i]);
+            newValues[i] = RPromise.checkEvaluate(frame, values[i], promiseProfile);
         }
         return new RArgsValuesAndNames(newValues, names);
     }
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 dab6ab839a852085d08d32c2934e9317b9f94e12..240ee7f5e91662cff9ac9568dcba13a678f712bb 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
@@ -27,6 +27,7 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.r.runtime.*;
 import com.oracle.truffle.r.runtime.env.*;
 
@@ -148,6 +149,46 @@ public final class RPromise extends RLanguageRep {
         return new RPromise(evalPolicy, type, env, closure);
     }
 
+    /**
+     * This class contains a profile of a specific promise evaluation site, i.e., a specific point
+     * in the AST where promises are inspected.
+     *
+     * This is useful to keep the amount of code included in Truffle compilation for each promise
+     * operation to a minimum.
+     */
+    public static final class PromiseProfile {
+        private final ConditionProfile isEvaluatedProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile underEvaluationProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile isNullEnvProfile = ConditionProfile.createBinaryProfile();
+
+        private final ConditionProfile isInlinedProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile isDefaultProfile = ConditionProfile.createBinaryProfile();
+        private final ConditionProfile isFrameForEnvProfile = ConditionProfile.createBinaryProfile();
+    }
+
+    public boolean isInlined(PromiseProfile profile) {
+        return profile.isInlinedProfile.profile(evalPolicy == EvalPolicy.INLINED);
+    }
+
+    /**
+     * @return Whether this promise is of {@link #type} {@link PromiseType#ARG_DEFAULT}.
+     */
+    public boolean isDefault(PromiseProfile profile) {
+        return profile.isDefaultProfile.profile(type == PromiseType.ARG_DEFAULT);
+    }
+
+    public boolean isNonArgument() {
+        return type == PromiseType.NO_ARG;
+    }
+
+    public boolean isNullEnv(PromiseProfile profile) {
+        return profile.isNullEnvProfile.profile(env == null);
+    }
+
+    public boolean isEvaluated(PromiseProfile profile) {
+        return profile.isEvaluatedProfile.profile(isEvaluated);
+    }
+
     /**
      * Evaluates this promise. If it has already been evaluated ({@link #isEvaluated()}),
      * {@link #getValue()} is returned.
@@ -155,13 +196,14 @@ public final class RPromise extends RLanguageRep {
      * @param frame The {@link VirtualFrame} in which the evaluation of this promise is forced
      * @return The value this promise resolves to
      */
-    public Object evaluate(VirtualFrame frame) {
-        if (isEvaluated) {
+    public Object evaluate(VirtualFrame frame, PromiseProfile profile) {
+        CompilerAsserts.compilationConstant(profile);
+        if (isEvaluated(profile)) {
             return value;
         }
 
         // Check for dependency cycle
-        if (underEvaluation) {
+        if (profile.underEvaluationProfile.profile(underEvaluation)) {
             SourceSection callSrc = RArguments.getCallSourceSection(frame);
             throw RError.error(callSrc, RError.Message.PROMISE_CYCLE);
         }
@@ -170,13 +212,13 @@ public final class RPromise extends RLanguageRep {
         try {
             underEvaluation = true;
 
-            // Evaluate this promises value!
+            // Evaluate this promise's value!
             // Performance: We can use frame directly
-            if (env != null && !isInOriginFrame(frame)) {
+            if (!isNullEnv(profile) && !isInOriginFrame(frame, profile)) {
                 SourceSection callSrc = frame != null ? RArguments.getCallSourceSection(frame) : null;
                 newValue = doEvalArgument(callSrc);
             } else {
-                assert isInOriginFrame(frame);
+                assert isInOriginFrame(frame, profile);
                 newValue = doEvalArgument(frame);
             }
 
@@ -228,73 +270,59 @@ public final class RPromise extends RLanguageRep {
      * call, but the callee frame and environment get created _after_ the call happened. This update
      * has to take place in AccessArgumentNode, just before arguments get stuffed into the fresh
      * environment for the function. Whether a {@link RPromise} needs one is determined by
-     * {@link #needsCalleeFrame()}!
+     * {@link #needsCalleeFrame(PromiseProfile)}!
      *
      * @param newEnv The REnvironment this promise is to be evaluated in
      */
-    public void updateEnv(REnvironment newEnv) {
+    public void updateEnv(REnvironment newEnv, PromiseProfile profile) {
         assert type == PromiseType.ARG_DEFAULT;
-        if (env == null && !isEvaluated) {
+        if (isNullEnv(profile) && !isEvaluated(profile)) {
             env = newEnv;
         }
     }
 
     /**
      * @param obj
+     * @param profile
      * @return If obj is a {@link RPromise}, it is evaluated and its result returned
      */
-    public static Object checkEvaluate(VirtualFrame frame, Object obj) {
+    public static Object checkEvaluate(VirtualFrame frame, Object obj, PromiseProfile profile) {
         if (obj instanceof RPromise) {
-            return ((RPromise) obj).evaluate(frame);
+            return ((RPromise) obj).evaluate(frame, profile);
         }
         return obj;
     }
 
     /**
      * Only to be called from AccessArgumentNode, and in combination with
-     * {@link #updateEnv(REnvironment)}!
+     * {@link #updateEnv(REnvironment,PromiseProfile)}!
      *
      * @return Whether this promise needs a callee environment set (see
-     *         {@link #updateEnv(REnvironment)})
+     *         {@link #updateEnv(REnvironment,PromiseProfile)})
      */
-    public boolean needsCalleeFrame() {
-        return evalPolicy == EvalPolicy.PROMISED && type == PromiseType.ARG_DEFAULT && env == null && !isEvaluated;
+    public boolean needsCalleeFrame(PromiseProfile profile) {
+        return !isInlined(profile) && isDefault(profile) && isNullEnv(profile) && !isEvaluated(profile);
     }
 
     /**
      * @param frame
+     * @param profile
      * @return Whether the given {@link RPromise} is in its origin context and thus can be resolved
      *         directly inside the AST.
      */
-    public boolean isInOriginFrame(VirtualFrame frame) {
-        if (evalPolicy == EvalPolicy.INLINED) {
+    public boolean isInOriginFrame(VirtualFrame frame, PromiseProfile profile) {
+        if (isInlined(profile)) {
             return true;
         }
-        assert evalPolicy == EvalPolicy.PROMISED;
 
-        if (type == PromiseType.ARG_DEFAULT && env == null) {
+        if (isDefault(profile) && isNullEnv(profile)) {
             return true;
         }
 
-        assert env != null;
         if (frame == null) {
             return false;
         }
-        return REnvironment.isFrameForEnv(frame, env);
-    }
-
-    /**
-     * @return {@link #evalPolicy}
-     */
-    public EvalPolicy getEvalPolicy() {
-        return evalPolicy;
-    }
-
-    /**
-     * @return {@link #type}
-     */
-    public PromiseType getType() {
-        return type;
+        return profile.isFrameForEnvProfile.profile(REnvironment.isFrameForEnv(frame, env));
     }
 
     /**
@@ -313,13 +341,6 @@ public final class RPromise extends RLanguageRep {
         return closure;
     }
 
-    /**
-     * @return Whether this promise is of {@link #type} {@link PromiseType#ARG_DEFAULT}.
-     */
-    public boolean isDefaulted() {
-        return type == PromiseType.ARG_DEFAULT;
-    }
-
     /**
      * @return {@link #env}
      */
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
index 018202432b9c451812b301eacc5c0508d7a90155..0598baed349c0e5f2af520c44557d7fe160a35aa 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java
@@ -159,6 +159,7 @@ public class TestBase {
             } else {
                 try {
                     expectedOutputManager = new ExpectedTestOutputManager(new File(expectedTestOutputURL.getPath()), false, false, false);
+                    fastROutputManager = new FastRTestOutputManager(null);
                 } catch (IOException ex) {
                     Assert.fail("error reading: " + expectedTestOutputURL.getPath() + ": " + ex);
                 }