From 2bee338b022e0d66192aeeef1db6501a2a6e9ae8 Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Tue, 31 Jan 2017 16:07:12 +0100
Subject: [PATCH] introduce visibleExecute and use whereever visibility is
 required

---
 .../com/oracle/truffle/r/engine/REngine.java  |  4 +-
 .../r/nodes/builtin/base/BasePackage.java     |  4 +-
 .../truffle/r/nodes/builtin/base/Return.java  | 55 ++++++++++++++---
 .../r/nodes/builtin/base/WithVisible.java     | 61 +++++++++++++++----
 .../truffle/r/nodes/InlineCacheNode.java      |  2 +-
 .../truffle/r/nodes/access/ConstantNode.java  | 24 +++++---
 .../nodes/access/WriteVariableSyntaxNode.java | 19 +++++-
 .../access/variables/ReadVariableNode.java    | 30 ++++++---
 .../r/nodes/builtin/RBuiltinRootNode.java     |  4 +-
 .../truffle/r/nodes/control/BlockNode.java    | 23 ++++++-
 .../truffle/r/nodes/control/IfNode.java       | 57 +++++++++++------
 .../control/ReplacementDispatchNode.java      | 13 +++-
 .../function/FunctionDefinitionNode.java      |  4 +-
 .../r/nodes/function/PromiseHelperNode.java   | 10 ++-
 .../r/nodes/function/RCallSpecialNode.java    | 16 +++++
 .../nodes/function/WrapArgumentBaseNode.java  | 15 ++++-
 .../visibility/SetVisibilityNode.java         | 13 +---
 .../oracle/truffle/r/runtime/nodes/RNode.java | 17 +++++-
 .../instrumentation/RNodeWrapperFactory.java  | 15 ++++-
 19 files changed, 297 insertions(+), 89 deletions(-)

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 87c08f476e..7dee98d92d 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
@@ -525,7 +525,7 @@ final class REngine implements Engine, Engine.Timings {
             VirtualFrame vf = prepareFrame(frame);
             Object result = null;
             try {
-                result = body.execute(vf);
+                result = body.visibleExecute(vf);
                 assert checkResult(result);
                 if (printResult && result != null) {
                     assert topLevel;
@@ -536,7 +536,7 @@ final class REngine implements Engine, Engine.Timings {
                 if (topLevel) {
                     RErrorHandling.printWarnings(suppressWarnings);
                 }
-                setVisibility.executeEndOfFunction(vf, this);
+                setVisibility.executeEndOfFunction(vf);
             } catch (RError e) {
                 CompilerDirectives.transferToInterpreter();
                 throw e;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index 369665c952..4910299b1d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -335,7 +335,7 @@ public class BasePackage extends RBuiltinPackage {
         add(EnvFunctions.UnlockBinding.class, EnvFunctionsFactory.UnlockBindingNodeGen::create);
         add(Eval.class, EvalNodeGen::create);
         add(RecordGraphics.class, RecordGraphics::create);
-        add(WithVisible.class, WithVisibleNodeGen::create);
+        add(WithVisible.class, WithVisibleNodeGen::create, WithVisible::createSpecial);
         add(Exists.class, ExistsNodeGen::create);
         add(Expression.class, ExpressionNodeGen::create);
         add(FastRContext.R.class, FastRContextFactory.RNodeGen::create);
@@ -567,7 +567,7 @@ public class BasePackage extends RBuiltinPackage {
         add(Repeat.class, RepeatNodeGen::create);
         add(RepeatInternal.class, RepeatInternalNodeGen::create);
         add(RepeatLength.class, RepeatLengthNodeGen::create);
-        add(Return.class, ReturnNodeGen::create);
+        add(Return.class, ReturnNodeGen::create, Return::createSpecial);
         add(Rhome.class, RhomeNodeGen::create);
         add(Rm.class, RmNodeGen::create);
         add(Round.class, RoundNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
index d2407dfe62..7001a7a168 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -25,16 +25,39 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RPromise;
+import com.oracle.truffle.r.runtime.nodes.RNode;
+
+final class ReturnSpecial extends RNode {
+
+    @Child private RNode value;
+    private final BranchProfile isPromiseEvalProfile = BranchProfile.create();
+
+    protected ReturnSpecial(RNode value) {
+        this.value = value;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        return Return.doReturn(frame, value.visibleExecute(frame), isPromiseEvalProfile);
+    }
+}
 
 /**
  * Return a value from the currently executing function, which is identified by the
@@ -42,18 +65,14 @@ import com.oracle.truffle.r.runtime.data.RNull;
  * delivered via a {@link ReturnException}, which is subsequently caught in the
  * {@link FunctionDefinitionNode}.
  */
-@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX)
+@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX, nonEvalArgs = {0})
 public abstract class Return extends RBuiltinNode {
 
-    private final BranchProfile isPromiseEvalProfile = BranchProfile.create();
-
-    @Override
-    public Object[] getDefaultParameterValues() {
-        return new Object[]{RNull.instance};
+    public static RNode createSpecial(@SuppressWarnings("unused") ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) {
+        return arguments.length == 1 ? new ReturnSpecial(arguments[0]) : null;
     }
 
-    @Specialization
-    protected Object returnFunction(VirtualFrame frame, Object value) {
+    static ReturnException doReturn(VirtualFrame frame, Object value, BranchProfile isPromiseEvalProfile) {
         RCaller call = RArguments.getCall(frame);
         while (call.isPromise()) {
             isPromiseEvalProfile.enter();
@@ -61,4 +80,22 @@ public abstract class Return extends RBuiltinNode {
         }
         throw new ReturnException(value, call);
     }
+
+    @Specialization
+    protected Object returnFunction(VirtualFrame frame, RPromise x,
+                    @Cached("new()") PromiseHelperNode promiseHelper,
+                    @Cached("create()") BranchProfile isPromiseEvalProfile,
+                    @Cached("create()") SetVisibilityNode visibility) {
+        if (x.isEvaluated()) {
+            visibility.execute(frame, true);
+        }
+        Object value = promiseHelper.evaluate(frame, x);
+        throw doReturn(frame, value, isPromiseEvalProfile);
+    }
+
+    @Specialization
+    protected RList returnFunction(VirtualFrame frame, @SuppressWarnings("unused") RMissing x,
+                    @Cached("create()") BranchProfile isPromiseEvalProfile) {
+        throw doReturn(frame, RNull.instance, isPromiseEvalProfile);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
index f1bdec68e3..5fb69cbcaa 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, 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
@@ -25,37 +25,76 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.function.visibility.GetVisibilityNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
 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.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RPromise;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.nodes.RNode;
+
+final class WithVisibleSpecial extends RNode {
+
+    @Child private RNode delegate;
+    @Child private GetVisibilityNode visibility = GetVisibilityNode.create();
+
+    protected WithVisibleSpecial(RNode delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public Object execute(VirtualFrame frame) {
+        Object value = delegate.visibleExecute(frame);
+        if (value == RMissing.instance) {
+            CompilerDirectives.transferToInterpreter();
+            throw RError.error(this, Message.ARGUMENT_MISSING, "x");
+        }
+        return RDataFactory.createList(new Object[]{value, RRuntime.asLogical(visibility.execute(frame))}, WithVisible.LISTNAMES);
+    }
+}
 
 // TODO The base package manual says this is a primitive but GNU R implements it as .Internal.
 // That causes problems as the .Internal adds another layer of visibility setting that
 // gets the wrong result. I believe that the only way to handle it as a .Internal would be to
 // set noEvalArgs and evaluate the argument here and set the visibility explicitly.
-@RBuiltin(name = "withVisible", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX)
+@RBuiltin(name = "withVisible", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX, nonEvalArgs = {0})
 public abstract class WithVisible extends RBuiltinNode {
 
-    private static final RStringVector LISTNAMES = (RStringVector) RDataFactory.createStringVector(new String[]{"value", "visible"}, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent();
+    static final RStringVector LISTNAMES = (RStringVector) RDataFactory.createStringVector(new String[]{"value", "visible"}, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent();
 
-    @Override
-    protected void createCasts(CastBuilder casts) {
-        casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x");
+    public static RNode createSpecial(@SuppressWarnings("unused") ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) {
+        return arguments.length == 1 ? new WithVisibleSpecial(arguments[0]) : null;
+    }
+
+    @Specialization
+    protected RList withVisible(VirtualFrame frame, RPromise x,
+                    @Cached("create()") GetVisibilityNode visibility,
+                    @Cached("new()") PromiseHelperNode promiseHelper) {
+        if (x.isEvaluated()) {
+            return RDataFactory.createList(new Object[]{x.getValue(), RRuntime.LOGICAL_TRUE}, LISTNAMES);
+        }
+        Object value = promiseHelper.evaluate(frame, x);
+        if (value == RMissing.instance) {
+            CompilerDirectives.transferToInterpreter();
+            throw RError.error(this, Message.ARGUMENT_MISSING, "x");
+        }
+        return RDataFactory.createList(new Object[]{value, RRuntime.asLogical(visibility.execute(frame))}, LISTNAMES);
     }
 
     @Specialization
-    protected RList withVisible(VirtualFrame frame, Object x,
-                    @Cached("create()") GetVisibilityNode visibility) {
-        Object[] data = new Object[]{x, RRuntime.asLogical(visibility.execute(frame))};
-        return RDataFactory.createList(data, LISTNAMES);
+    protected RList withVisible(@SuppressWarnings("unused") RMissing x) {
+        CompilerDirectives.transferToInterpreter();
+        throw RError.error(this, Message.ARGUMENT_MISSING, "x");
     }
 }
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 8cc35b81b0..40622acfcd 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
@@ -71,7 +71,7 @@ public abstract class InlineCacheNode extends RBaseNode {
         } else {
             vf = SubstituteVirtualFrame.create(frame.materialize());
         }
-        return reified.execute(vf);
+        return reified.visibleExecute(vf);
     }
 
     protected RNode cache(Object value) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java
index 9cdd88d0e8..5a339754ec 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.access;
 
 import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.source.SourceSection;
@@ -39,7 +40,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
 public abstract class ConstantNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxConstant {
 
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     private ConstantNode(SourceSection sourceSection) {
         super(sourceSection);
@@ -60,13 +61,23 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
     @Override
     public abstract Object getValue();
 
-    protected final void handleVisibility(VirtualFrame frame) {
-        visibility.execute(frame, true);
+    @Override
+    public final void voidExecute(VirtualFrame frame) {
+        // nothing to do
     }
 
     @Override
     public final Object execute(VirtualFrame frame) {
-        handleVisibility(frame);
+        return getValue();
+    }
+
+    @Override
+    public final Object visibleExecute(VirtualFrame frame) {
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
         return getValue();
     }
 
@@ -113,7 +124,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
 
         @Override
         public double executeDouble(VirtualFrame frame) {
-            handleVisibility(frame);
             return doubleValue;
         }
     }
@@ -136,7 +146,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
 
         @Override
         public byte executeByte(VirtualFrame frame) {
-            handleVisibility(frame);
             return logicalValue;
         }
     }
@@ -159,7 +168,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax
 
         @Override
         public int executeInteger(VirtualFrame frame) {
-            handleVisibility(frame);
             return intValue;
         }
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java
index a442c0747a..2840ed66f3 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.access;
 
 import static com.oracle.truffle.api.nodes.NodeCost.NONE;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.api.source.SourceSection;
@@ -42,7 +43,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
 public final class WriteVariableSyntaxNode extends OperatorNode {
 
     @Child private WriteVariableNode write;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     private final RSyntaxElement lhs;
 
@@ -68,9 +69,23 @@ public final class WriteVariableSyntaxNode extends OperatorNode {
         assert write != null;
     }
 
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        write.execute(frame);
+    }
+
     @Override
     public Object execute(VirtualFrame frame) {
+        return write.execute(frame);
+    }
+
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
         Object result = write.execute(frame);
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
         visibility.execute(frame, false);
         return result;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
index cf0585f4b1..990fdbfe45 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -125,7 +125,7 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
 
     @Child private PromiseHelperNode promiseHelper;
     @Child private CheckTypeNode checkTypeNode;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     @CompilationFinal private FrameLevel read;
     @CompilationFinal private boolean needsCopying;
@@ -167,20 +167,34 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
         return identifier instanceof String;
     }
 
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        executeInternal(frame, frame);
+    }
+
     @Override
     public Object execute(VirtualFrame frame) {
-        return executeInternal(frame, kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(frame)) : frame);
+        return executeInternal(frame, frame);
+    }
+
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
+        assert kind != ReadKind.Silent;
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
+        return executeInternal(frame, frame);
     }
 
     public Object execute(VirtualFrame frame, Frame variableFrame) {
         assert frame != null;
-        return executeInternal(frame, kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(variableFrame)) : variableFrame);
+        return executeInternal(frame, variableFrame);
     }
 
-    private Object executeInternal(VirtualFrame frame, Frame variableFrame) {
-        if (kind != ReadKind.Silent) {
-            visibility.execute(frame, true);
-        }
+    private Object executeInternal(VirtualFrame frame, Frame initialFrame) {
+        Frame variableFrame = kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(initialFrame)) : initialFrame;
 
         Object result;
         if (read == null) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java
index 9e0044e241..88652dcff5 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -89,7 +89,7 @@ public final class RBuiltinRootNode extends RRootNode {
             throw new RInternalError(e, "internal error");
         } finally {
             visibility.execute(frame, factory.getVisibility());
-            visibility.executeEndOfFunction(frame, this);
+            visibility.executeEndOfFunction(frame);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java
index 6b94d1cb09..e660d18e3c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.control;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.source.SourceSection;
@@ -41,7 +42,7 @@ public final class BlockNode extends OperatorNode {
     public static final RNode[] EMPTY_BLOCK = new RNode[0];
 
     @Children protected final RNode[] sequence;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     public BlockNode(SourceSection src, RSyntaxLookup operator, RNode[] sequence) {
         super(src, operator);
@@ -55,7 +56,6 @@ public final class BlockNode extends OperatorNode {
     @Override
     @ExplodeLoop
     public Object execute(VirtualFrame frame) {
-        visibility.execute(frame, true);
         if (sequence.length == 0) {
             return RNull.instance;
         }
@@ -73,6 +73,23 @@ public final class BlockNode extends OperatorNode {
         }
     }
 
+    @Override
+    @ExplodeLoop
+    public Object visibleExecute(VirtualFrame frame) {
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
+        if (sequence.length == 0) {
+            return RNull.instance;
+        }
+        for (int i = 0; i < sequence.length - 1; i++) {
+            sequence[i].voidExecute(frame);
+        }
+        return sequence[sequence.length - 1].visibleExecute(frame);
+    }
+
     @Override
     public RSyntaxNode[] getSyntaxArguments() {
         return RASTUtils.asSyntaxNodes(sequence);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java
index fd5b395b0c..ae9a2cf35d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -42,7 +42,7 @@ public final class IfNode extends OperatorNode {
     @Child private ConvertBooleanNode condition;
     @Child private RNode thenPart;
     @Child private RNode elsePart;
-    @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
+    @Child private SetVisibilityNode visibility;
 
     private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile();
 
@@ -53,30 +53,32 @@ public final class IfNode extends OperatorNode {
         this.elsePart = elsePart == null ? null : elsePart.asRNode();
     }
 
-    /**
-     * Result visibility of an {@code if} expression is not only a property of the {@code if}
-     * builtin; it also depends on whether there is an else branch or not, and on the condition. For
-     * instance, the expression {@code if (FALSE) 23} will evaluate to {@code NULL}, but the result
-     * will not be printed in the shell. Conversely, {@code NULL} will be printed for
-     * {@code if (FALSE) 23 else NULL} because the else branch is given.
-     */
-
-    @Override
-    public Object execute(VirtualFrame frame) {
+    private boolean evaluateCondition(VirtualFrame frame) {
         byte cond = condition.executeByte(frame);
-        visibility.execute(frame, elsePart != null || cond == RRuntime.LOGICAL_TRUE);
-
         if (cond == RRuntime.LOGICAL_NA) {
-            // NA is the only remaining option
             CompilerDirectives.transferToInterpreter();
             throw RError.error(this, RError.Message.NA_UNEXP);
         }
+        assert cond == RRuntime.LOGICAL_FALSE || cond == RRuntime.LOGICAL_TRUE : "logical value none of TRUE|FALSE|NA";
+        return conditionProfile.profile(cond == RRuntime.LOGICAL_TRUE);
+    }
 
-        if (conditionProfile.profile(cond == RRuntime.LOGICAL_TRUE)) {
-            return thenPart.execute(frame);
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        if (evaluateCondition(frame)) {
+            thenPart.voidExecute(frame);
         } else {
-            assert cond == RRuntime.LOGICAL_FALSE : "logical value none of TRUE|FALSE|NA";
+            if (elsePart != null) {
+                elsePart.voidExecute(frame);
+            }
+        }
+    }
 
+    @Override
+    public Object execute(VirtualFrame frame) {
+        if (evaluateCondition(frame)) {
+            return thenPart.execute(frame);
+        } else {
             if (elsePart != null) {
                 return elsePart.execute(frame);
             } else {
@@ -85,6 +87,25 @@ public final class IfNode extends OperatorNode {
         }
     }
 
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
+        if (evaluateCondition(frame)) {
+            return thenPart.visibleExecute(frame);
+        } else {
+            if (elsePart != null) {
+                return elsePart.visibleExecute(frame);
+            } else {
+                // otherwise: return invisible NULL
+                if (visibility == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    visibility = insert(SetVisibilityNode.create());
+                }
+                visibility.execute(frame, false);
+                return RNull.instance;
+            }
+        }
+    }
+
     public ConvertBooleanNode getCondition() {
         return condition;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java
index 144d1200fd..ffd2040d06 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -70,16 +70,23 @@ public final class ReplacementDispatchNode extends OperatorNode {
         this.tempNamesStartIndex = tempNamesStartIndex;
     }
 
+    @Override
+    public void voidExecute(VirtualFrame frame) {
+        CompilerDirectives.transferToInterpreterAndInvalidate();
+        create(true).voidExecute(frame);
+    }
+
     @Override
     public Object execute(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         return create(false).execute(frame);
+
     }
 
     @Override
-    public void voidExecute(VirtualFrame frame) {
+    public Object visibleExecute(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
-        create(true).voidExecute(frame);
+        return create(false).visibleExecute(frame);
     }
 
     public RNode create(boolean isVoid) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
index 33b8ab9319..3d5bd7b6d2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
@@ -251,7 +251,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
             verifyEnclosingAssumptions(frame);
             setupDispatchSlots(frame);
             saveArguments.execute(frame);
-            Object result = body.execute(frame);
+            Object result = body.visibleExecute(frame);
             normalExit.enter();
             return result;
         } catch (ReturnException ex) {
@@ -290,12 +290,12 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
              * has no exit handlers (by fiat), so any exceptions from onExits handlers will be
              * caught above.
              */
-            visibility.executeEndOfFunction(frame, this);
             if (argPostProcess != null) {
                 resetArgs.enter();
                 argPostProcess.execute(frame);
             }
             if (runOnExitHandlers) {
+                visibility.executeEndOfFunction(frame);
                 if (!noHandlerStackSlot.isValid() && frame.isObject(handlerStackSlot)) {
                     try {
                         RErrorHandling.restoreHandlerStack(frame.getObject(handlerStackSlot));
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 ba04478ae0..75bf2c9831 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -40,6 +40,7 @@ import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.InlineCacheNode;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -383,6 +384,8 @@ public class PromiseHelperNode extends RBaseNode {
     private static final int GENERIC = -2;
     @CompilationFinal private int cachedWrapIndex = UNINITIALIZED;
 
+    @Child private SetVisibilityNode visibility;
+
     /**
      * Returns {@link EagerPromise#getEagerValue()} profiled.
      */
@@ -419,6 +422,11 @@ public class PromiseHelperNode extends RBaseNode {
                 }
             }
         }
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, true);
         return eagerValueProfile.profile(o);
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
index 15cc7f5aa2..ce167a93b4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java
@@ -29,11 +29,13 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
+import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RDispatch;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RVisibility;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RSpecialFactory;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -120,10 +122,12 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
 
     @Child private RNode functionNode;
     @Child private RNode special;
+    @Child private SetVisibilityNode visibility;
 
     private final RSyntaxNode[] arguments;
     private final ArgumentsSignature signature;
     private final RFunction expectedFunction;
+    private final RVisibility visible;
 
     /**
      * If this is true, then any bailout should simply be forwarded by re-throwing the exception.
@@ -143,6 +147,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         this.functionNode = functionNode;
         this.arguments = arguments;
         this.signature = signature;
+        this.visible = expectedFunction.getRBuiltin().getVisibility();
     }
 
     /**
@@ -310,6 +315,17 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         return execute(frame, functionNode.execute(frame));
     }
 
+    @Override
+    public Object visibleExecute(VirtualFrame frame) {
+        Object result = execute(frame, functionNode.execute(frame));
+        if (visibility == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            visibility = insert(SetVisibilityNode.create());
+        }
+        visibility.execute(frame, visible);
+        return result;
+    }
+
     @Override
     public RSyntaxElement getSyntaxLHS() {
         return functionNode == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : functionNode.asRSyntaxNode();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
index cb11340263..ebc6853f82 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.function;
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage;
 import com.oracle.truffle.r.runtime.nodes.RNode;
@@ -46,13 +47,23 @@ public abstract class WrapArgumentBaseNode extends RNode {
         return operand;
     }
 
+    @Override
+    public final void voidExecute(VirtualFrame frame) {
+        throw RInternalError.shouldNotReachHere();
+    }
+
     @Override
     public final Object execute(VirtualFrame frame) {
-        assert operand != null;
         Object result = operand.execute(frame);
         return execute(frame, result);
     }
 
+    @Override
+    public final Object visibleExecute(VirtualFrame frame) {
+        Object result = operand.visibleExecute(frame);
+        return execute(frame, result);
+    }
+
     public Object execute(VirtualFrame frame, Object result) {
         if (isShareable.profile(result instanceof RSharingAttributeStorage)) {
             return handleShareable(frame, (RSharingAttributeStorage) result);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
index c20ab69256..a259f498ad 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -88,19 +87,11 @@ public final class SetVisibilityNode extends Node {
      * Needs to be called at the end of each function, so that the visibility is transferred from
      * the current frame into the {@link RCaller}.
      */
-    public void executeEndOfFunction(VirtualFrame frame, RootNode root) {
+    public void executeEndOfFunction(VirtualFrame frame) {
         ensureFrameSlot(frame);
         try {
             if (frame.isBoolean(frameSlot)) {
                 RArguments.getCall(frame).setVisibility(frame.getBoolean(frameSlot) == Boolean.TRUE);
-            } else {
-                CompilerDirectives.transferToInterpreter();
-                /*
-                 * Most likely the (only) builtin call in the function was configured to
-                 * RVisibility.CUSTOM and didn't actually set the visibility. Another possible
-                 * problem is a node that is created by RASTBuilder that does not set visibility.
-                 */
-                throw RInternalError.shouldNotReachHere("visibility not set at the end of " + root.getName());
             }
         } catch (FrameSlotTypeException e) {
             throw RInternalError.shouldNotReachHere(e);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
index c07a69b873..8629846c53 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
@@ -63,17 +63,28 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
 @Instrumentable(factory = com.oracle.truffle.r.runtime.nodes.instrumentation.RNodeWrapperFactory.class)
 public abstract class RNode extends RBaseNode implements RInstrumentableNode {
 
+    /**
+     * Normal execute function that is called when the return value, but not its visibility is
+     * needed.
+     */
     public abstract Object execute(VirtualFrame frame);
 
     /**
-     * This function can be called when the result is not needed, and normally just dispatches to
-     * {@link #execute(VirtualFrame)}. Its name does not start with "execute" so that the DSL does
-     * not treat it like an execute function.
+     * This function is called when the result is not needed. Its name does not start with "execute"
+     * so that the DSL does not treat it like an execute function.
      */
     public void voidExecute(VirtualFrame frame) {
         execute(frame);
     }
 
+    /**
+     * This function is called when both the result and the result's visibility are needed. Its name
+     * does not start with "execute" so that the DSL does not treat it like an execute function.
+     */
+    public Object visibleExecute(VirtualFrame frame) {
+        return execute(frame);
+    }
+
     public int executeInteger(VirtualFrame frame) throws UnexpectedResultException {
         Object value = execute(frame);
         assert value != null;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java
index d79719b63e..b385fc6fe9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, 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
@@ -80,6 +80,19 @@ public final class RNodeWrapperFactory implements InstrumentableFactory<RNode> {
             }
         }
 
+        @Override
+        public Object visibleExecute(VirtualFrame frame) {
+            try {
+                probeNode.onEnter(frame);
+                Object returnValue = delegate.visibleExecute(frame);
+                probeNode.onReturnValue(frame, returnValue);
+                return returnValue;
+            } catch (Throwable t) {
+                probeNode.onReturnExceptional(frame, t);
+                throw t;
+            }
+        }
+
         @Override
         public RSyntaxNode getRSyntaxNode() {
             return delegate.asRSyntaxNode();
-- 
GitLab