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 b7cc4812af454213b9f08f7492e38b9332378514..ee090e1c1ac7134433c540a1242dc2a56006ab89 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
@@ -77,6 +77,7 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
 import com.oracle.truffle.r.runtime.ReturnException;
+import com.oracle.truffle.r.runtime.RootWithBody;
 import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
 import com.oracle.truffle.r.runtime.ThreadTimings;
 import com.oracle.truffle.r.runtime.Utils;
@@ -476,7 +477,7 @@ final class REngine implements Engine, Engine.Timings {
      * context of that frame. Note that passing only this one frame argument, strictly spoken,
      * violates the frame layout as set forth in {@link RArguments}. This is for internal use only.
      */
-    private final class AnonymousRootNode extends RootNode {
+    private final class AnonymousRootNode extends RootNode implements RootWithBody {
 
         private final ValueProfile frameTypeProfile = ValueProfile.createClassProfile();
         private final ConditionProfile isVirtualFrameProfile = ConditionProfile.createBinaryProfile();
@@ -566,6 +567,11 @@ final class REngine implements Engine, Engine.Timings {
         public boolean isCloningAllowed() {
             return false;
         }
+
+        @Override
+        public RNode getBody() {
+            return body;
+        }
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/SpecialCallTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/SpecialCallTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b72e022b321a7d8fa76f41a506f474f6bd84ab90
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/SpecialCallTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.oracle.truffle.api.RootCallTarget;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.r.engine.TruffleRLanguage;
+import com.oracle.truffle.r.nodes.access.WriteVariableSyntaxNode;
+import com.oracle.truffle.r.nodes.control.BlockNode;
+import com.oracle.truffle.r.nodes.control.ReplacementDispatchNode;
+import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.function.RCallSpecialNode;
+import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.FastROptions;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RootWithBody;
+import com.oracle.truffle.r.runtime.data.RExpression;
+import com.oracle.truffle.r.runtime.data.RLanguage;
+import com.oracle.truffle.r.runtime.env.REnvironment;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxCall;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor;
+
+public class SpecialCallTest extends TestBase {
+    private static final class CountCallsVisitor extends RSyntaxVisitor<Void> {
+
+        public int normal;
+        public int special;
+
+        CountCallsVisitor(RootCallTarget callTarget) {
+            accept(((RootWithBody) callTarget.getRootNode()).getBody().asRSyntaxNode());
+        }
+
+        @Override
+        protected Void visit(RSyntaxCall element) {
+            if (element instanceof RCallSpecialNode) {
+                special++;
+            } else if (element instanceof RCallNode) {
+                normal++;
+            } else {
+                assert element instanceof ReplacementDispatchNode || element instanceof WriteVariableSyntaxNode || element instanceof BlockNode : "unexpected node while testing";
+            }
+            accept(element.getSyntaxLHS());
+            for (RSyntaxElement arg : element.getSyntaxArguments()) {
+                accept(arg);
+            }
+            return null;
+        }
+
+        @Override
+        protected Void visit(RSyntaxConstant element) {
+            return null;
+        }
+
+        @Override
+        protected Void visit(RSyntaxLookup element) {
+            return null;
+        }
+
+        @Override
+        protected Void visit(RSyntaxFunction element) {
+            for (RSyntaxElement arg : element.getSyntaxArgumentDefaults()) {
+                accept(arg);
+            }
+            accept(element.getSyntaxBody());
+            return null;
+        }
+    }
+
+    private static final class PrintCallsVisitor extends RSyntaxVisitor<Void> {
+
+        private String indent = "";
+
+        void print(RootCallTarget callTarget) {
+            System.out.println();
+            accept(((RootWithBody) callTarget.getRootNode()).getBody().asRSyntaxNode());
+        }
+
+        @Override
+        protected Void visit(RSyntaxCall element) {
+            System.out.println(indent + "call " + element.getClass().getSimpleName());
+            indent += "    ";
+            System.out.println(indent.substring(2) + "lhs:");
+            accept(element.getSyntaxLHS());
+            printArgs(element.getSyntaxSignature(), element.getSyntaxArguments());
+            indent = indent.substring(4);
+            return null;
+        }
+
+        @Override
+        protected Void visit(RSyntaxConstant element) {
+            System.out.println(indent + "constant " + element.getClass().getSimpleName() + " " + element.getValue().getClass().getSimpleName() + " " + element.getValue());
+            return null;
+        }
+
+        @Override
+        protected Void visit(RSyntaxLookup element) {
+            System.out.println(indent + "lookup " + element.getClass().getSimpleName() + " " + element.getIdentifier());
+            return null;
+        }
+
+        @Override
+        protected Void visit(RSyntaxFunction element) {
+            System.out.println(indent + "function " + element.getClass().getSimpleName());
+            indent += "    ";
+            printArgs(element.getSyntaxSignature(), element.getSyntaxArgumentDefaults());
+            indent = indent.substring(4);
+            for (RSyntaxElement arg : element.getSyntaxArgumentDefaults()) {
+                accept(arg);
+            }
+            System.out.println(indent.substring(2) + "body:");
+            accept(element.getSyntaxBody());
+            return null;
+        }
+
+        private void printArgs(ArgumentsSignature signature, RSyntaxElement[] arguments) {
+            for (int i = 0; i < arguments.length; i++) {
+                System.out.println(indent.substring(2) + "arg " + (signature.getName(i) == null ? "<unnamed>" : signature.getName(i)));
+                accept(arguments[i]);
+            }
+        }
+    }
+
+    @Test
+    public void testBasic() {
+        // check a case with no calls
+        assertCallCounts("library(stats)", 0, 1, 0, 1);
+    }
+
+    @Test
+    public void testArithmetic() {
+        assertCallCounts("1 + 1", 1, 0, 1, 0);
+        assertCallCounts("1 + 1 * 2 + 4", 3, 0, 3, 0);
+
+        assertCallCounts("{ a <- 1; b <- 2; a + b }", 1, 0, 1, 0);
+        assertCallCounts("{ a <- 1; b <- 2; c <- 3; a + b * 2 * c}", 3, 0, 3, 0);
+
+        assertCallCounts("{ a <- data.frame(a=1); b <- 2; c <- 3; a + b * 2 * c}", 3, 1, 2, 2);
+        assertCallCounts("{ a <- 1; b <- data.frame(a=1); c <- 3; a + b * 2 * c}", 3, 1, 0, 4);
+
+        assertCallCounts("1 %*% 1", 0, 1, 0, 1);
+    }
+
+    @Test
+    public void testSubset() {
+        assertCallCounts("{ a <- 1:10; a[1] }", 1, 1, 1, 1);
+        assertCallCounts("{ a <- c(1,2,3,4); a[2] }", 1, 1, 1, 1);
+        assertCallCounts("{ a <- c(1,2,3,4); a[4] }", 1, 1, 1, 1);
+        assertCallCounts("{ a <- list(c(1,2,3,4),2,3); a[1] }", 1, 2, 1, 2);
+
+        assertCallCounts("{ a <- c(1,2,3,4); a[0.1] }", 1, 1, 0, 2);
+        assertCallCounts("{ a <- c(1,2,3,4); a[5] }", 1, 1, 0, 2);
+        assertCallCounts("{ a <- c(1,2,3,4); a[0] }", 1, 1, 0, 2);
+        assertCallCounts("{ a <- c(1,2,3,4); a[-1] }", 0, 3, 0, 3); // "-1" is a unary expression
+        assertCallCounts("{ a <- c(1,2,3,4); b <- -1; a[b] }", 1, 2, 0, 3);
+        assertCallCounts("{ a <- c(1,2,3,4); a[NA_integer_] }", 1, 1, 0, 2);
+    }
+
+    @Test
+    public void testSubscript() {
+        assertCallCounts("{ a <- 1:10; a[[1]] }", 1, 1, 1, 1);
+        assertCallCounts("{ a <- c(1,2,3,4); a[[2]] }", 1, 1, 1, 1);
+        assertCallCounts("{ a <- c(1,2,3,4); a[[4]] }", 1, 1, 1, 1);
+        assertCallCounts("{ a <- list(c(1,2,3,4),2,3); a[[1]] }", 1, 2, 1, 2);
+        assertCallCounts("{ a <- list(a=c(1,2,3,4),2,3); a[[1]] }", 1, 2, 1, 2);
+        assertCallCounts("{ a <- c(1,2,3,4); a[[0.1]] }", 1, 1, 1, 1);
+
+        assertCallCounts("{ a <- c(1,2,3,4); a[[5]] }", 1, 1, 0, 2);
+        assertCallCounts("{ a <- c(1,2,3,4); a[[0]] }", 1, 1, 0, 2);
+        assertCallCounts("{ a <- c(1,2,3,4); b <- -1; a[[b]] }", 1, 2, 0, 3);
+        assertCallCounts("{ a <- c(1,2,3,4); a[[NA_integer_]] }", 1, 1, 0, 2);
+    }
+
+    private static void assertCallCounts(String str, int initialSpecialCount, int initialNormalCount, int finalSpecialCount, int finalNormalCount) {
+        if (!FastROptions.UseSpecials.getBooleanValue()) {
+            return;
+        }
+        Source source = Source.newBuilder(str).mimeType(TruffleRLanguage.MIME).name("test").build();
+
+        RExpression expression = testVMContext.getThisEngine().parse(source);
+        assert expression.getLength() == 1;
+        RootCallTarget callTarget = testVMContext.getThisEngine().makePromiseCallTarget(((RLanguage) expression.getDataAt(0)).getRep().asRSyntaxNode().asRNode(), "test");
+
+        try {
+            CountCallsVisitor count1 = new CountCallsVisitor(callTarget);
+            Assert.assertEquals("initial special call count '" + str + "': ", initialSpecialCount, count1.special);
+            Assert.assertEquals("initial normal call count '" + str + "': ", initialNormalCount, count1.normal);
+
+            try {
+                callTarget.call(REnvironment.globalEnv().getFrame());
+            } catch (RError e) {
+                // ignore
+            }
+
+            CountCallsVisitor count2 = new CountCallsVisitor(callTarget);
+            Assert.assertEquals("special call count after first call '" + str + "': ", finalSpecialCount, count2.special);
+            Assert.assertEquals("normal call count after first call '" + str + "': ", finalNormalCount, count2.normal);
+
+            try {
+                callTarget.call(REnvironment.globalEnv().getFrame());
+            } catch (RError e) {
+                // ignore
+            }
+
+            CountCallsVisitor count3 = new CountCallsVisitor(callTarget);
+            Assert.assertEquals("special call count after second call '" + str + "': ", finalSpecialCount, count3.special);
+            Assert.assertEquals("normal call count after second call '" + str + "': ", finalNormalCount, count3.normal);
+        } catch (AssertionError e) {
+            new PrintCallsVisitor().print(callTarget);
+            throw e;
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
index 1e0d45dfc2e5aa3d9ca3f66eb0c9cb9367680a62..936e2babd89f1a40e0485779285835a07c622653 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.nodes.access.RemoveAndAnswerNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.function.RCallSpecialNode;
-import com.oracle.truffle.r.nodes.function.RCallSpecialNode.RecursiveSpecialBailout;
 import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode;
 import com.oracle.truffle.r.nodes.unary.GetNonSharedNodeGen;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
@@ -241,10 +240,10 @@ abstract class ReplacementNode extends OperatorNode {
             RNode extractFunc = target;
             for (int i = calls.size() - 1; i >= 1; i--) {
                 extractFunc = createSpecialFunctionQuery(calls.get(i), extractFunc.asRSyntaxNode(), codeBuilderContext);
-                ((RCallSpecialNode) extractFunc).setPropagateFullCallNeededException(true);
+                ((RCallSpecialNode) extractFunc).setPropagateFullCallNeededException();
             }
             this.replaceCall = (RCallSpecialNode) createFunctionUpdate(source, extractFunc.asRSyntaxNode(), ReadVariableNode.create("*rhs*" + tempNamesStartIndex), calls.get(0), codeBuilderContext);
-            this.replaceCall.setPropagateFullCallNeededException(true);
+            this.replaceCall.setPropagateFullCallNeededException();
         }
 
         @Override
@@ -255,7 +254,7 @@ abstract class ReplacementNode extends OperatorNode {
                 // shared, it could not be extracted from a shared container (list), so we should be
                 // OK with not calling any other update function and just update the value directly.
                 replaceCall.execute(frame);
-            } catch (FullCallNeededException | RecursiveSpecialBailout e) {
+            } catch (FullCallNeededException e) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 replace(new GenericReplacementNode(getLazySourceSection(), operator, target, lhs, rhs, calls, targetVarName, isSuper, tempNamesStartIndex)).executeReplacement(frame);
             }
@@ -295,10 +294,10 @@ abstract class ReplacementNode extends OperatorNode {
             RNode extractFunc = target;
             for (int i = calls.size() - 1; i >= 1; i--) {
                 extractFunc = createSpecialFunctionQuery(calls.get(i), extractFunc.asRSyntaxNode(), codeBuilderContext);
-                ((RCallSpecialNode) extractFunc).setPropagateFullCallNeededException(true);
+                ((RCallSpecialNode) extractFunc).setPropagateFullCallNeededException();
             }
             this.replaceCall = (RCallSpecialNode) createFunctionUpdate(source, extractFunc.asRSyntaxNode(), rhs.asRSyntaxNode(), calls.get(0), codeBuilderContext);
-            this.replaceCall.setPropagateFullCallNeededException(true);
+            this.replaceCall.setPropagateFullCallNeededException();
         }
 
         @Override
@@ -316,17 +315,16 @@ abstract class ReplacementNode extends OperatorNode {
                 // shared, it could not be extracted from a shared container (list), so we should be
                 // OK with not calling any other update function and just update the value directly.
                 replaceCall.execute(frame);
-            } catch (FullCallNeededException | RecursiveSpecialBailout e) {
+            } catch (FullCallNeededException e) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 GenericReplacementNode replacement = replace(new GenericReplacementNode(getLazySourceSection(), operator, target, lhs, rhs, calls, targetVarName, isSuper, tempNamesStartIndex));
 
-                Object rhsValue = e instanceof FullCallNeededException ? ((FullCallNeededException) e).rhsValue : ((RecursiveSpecialBailout) e).rhsValue;
-                if (rhsValue == null) {
+                if (e.rhsValue == null) {
                     // we haven't queried the rhs value yet
                     replacement.voidExecute(frame);
                 } else {
                     // rhs was already queried, so pass it along
-                    replacement.voidExecuteWithRhs(frame, rhsValue);
+                    replacement.voidExecuteWithRhs(frame, e.rhsValue);
                 }
             }
         }
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 8259598aa45b9f78292eed86efc0d6672be9283c..830bf51331a185cf2cc207e1bc7c22577f1aace2 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
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.function;
 
-import java.util.Arrays;
-
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.frame.VirtualFrame;
@@ -37,7 +35,6 @@ import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.builtins.RSpecialFactory;
-import com.oracle.truffle.r.runtime.builtins.RSpecialFactory.FullCallNeededException;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RPromise;
@@ -98,7 +95,6 @@ final class PeekLocalVariableNode extends RNode implements RSyntaxLookup {
 
 public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode, RSyntaxCall {
 
-    private static final int NO_RECURSIVE_ARGUMENT_INDEX = -1;
     private static final boolean useSpecials = FastROptions.UseSpecials.getBooleanValue();
 
     // currently cannot be RSourceSectionNode because of TruffleDSL restrictions
@@ -129,12 +125,16 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
     private final RFunction expectedFunction;
 
     /**
-     * If this instance is argument of another RCallSpecialNode (parent), then this will be the
-     * index into the parent arguments array, otherwise {@link #NO_RECURSIVE_ARGUMENT_INDEX}.
+     * If this is true, then any bailout should simply be forwarded by re-throwing the exception.
      */
-    private int argumentIndex = NO_RECURSIVE_ARGUMENT_INDEX;
     private boolean propagateFullCallNeededException;
 
+    /**
+     * If this is non-null, then any bailout should lead to be forwarded by re-throwing the
+     * exception after replacing itself with a proper call node.
+     */
+    private RCallSpecialNode callSpecialParent;
+
     private RCallSpecialNode(SourceSection sourceSection, RNode functionNode, RFunction expectedFunction, RSyntaxNode[] arguments, ArgumentsSignature signature, RNode special) {
         this.sourceSectionR = sourceSection;
         this.expectedFunction = expectedFunction;
@@ -206,7 +206,6 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
                     localArguments[i] = RContext.getASTBuilder().process(arguments[i]).asRNode();
                 } else {
                     assert arguments[i] instanceof RCallSpecialNode;
-                    ((RCallSpecialNode) arguments[i]).setArgumentIndex(i);
                     localArguments[i] = arguments[i].asRNode();
                 }
             }
@@ -219,7 +218,15 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         RFunction expectedFunction = RContext.lookupBuiltin(name);
         RInternalError.guarantee(expectedFunction != null);
 
-        return new RCallSpecialNode(sourceSection, functionNode, expectedFunction, arguments, signature, special);
+        RCallSpecialNode callSpecial = new RCallSpecialNode(sourceSection, functionNode, expectedFunction, arguments, signature, special);
+        for (int i = 0; i < arguments.length; i++) {
+            if (!inReplace || !contains(ignoredArguments, i)) {
+                if (arguments[i] instanceof RCallSpecialNode) {
+                    ((RCallSpecialNode) arguments[i]).setCallSpecialParent(callSpecial);
+                }
+            }
+        }
+        return callSpecial;
     }
 
     private static boolean contains(int[] ignoredArguments, int index) {
@@ -239,45 +246,30 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
                 throw RSpecialFactory.throwFullCallNeeded();
             }
             return special.execute(frame);
-        } catch (RecursiveSpecialBailout bailout) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            throwOnRecursiveSpecial(bailout.rhsValue);
-            return replace(getRCallNode(rewriteSpecialArgument(bailout))).execute(frame, function);
         } catch (RSpecialFactory.FullCallNeededException e) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            throwOnRecursiveSpecial(e.rhsValue);
-            return replace(getRCallNode()).execute(frame, function);
-        }
-    }
-
-    private void throwOnRecursiveSpecial(Object rhsValue) {
-        if (isRecursiveSpecial()) {
-            throw new RecursiveSpecialBailout(argumentIndex, rhsValue);
+            if (propagateFullCallNeededException) {
+                throw e;
+            }
+            RCallNode callNode = getRCallNode();
+            for (RSyntaxElement arg : arguments) {
+                if (arg instanceof RCallSpecialNode) {
+                    ((RCallSpecialNode) arg).setCallSpecialParent(null);
+                }
+            }
+            if (callSpecialParent != null) {
+                RSyntaxNode[] args = callSpecialParent.arguments;
+                for (int i = 0; i < args.length; i++) {
+                    if (args[i] == this) {
+                        args[i] = callNode;
+                    }
+                }
+                throw e;
+            }
+            return replace(callNode).execute(frame, function);
         }
     }
 
-    private RSyntaxNode[] rewriteSpecialArgument(RecursiveSpecialBailout bailout) {
-        // Note: other arguments that may be specials too, stay specials, their parent node will be
-        // changed in createRCallNode, but we are never going to use the original parent, which is
-        // the 'this.special' node that bailed out.
-        // Note 2: we have to make a copy of the array, because this node may have been shallow
-        // copied and the other copy will keep its copied parent, i.e. bailout exception from here
-        // will not reach the copied parent, but we would rewrite one of its arguments to full-blown
-        // RCallNode. It seems that bailing out happens less frequently than Node.copy, so we do the
-        // copying here.
-        RSyntaxNode[] newArguments = Arrays.copyOf(arguments, arguments.length);
-        RCallSpecialNode arg = (RCallSpecialNode) arguments[bailout.argumentIndex];
-        newArguments[bailout.argumentIndex] = arg.getRCallNode();
-        return newArguments;
-    }
-
-    private boolean isRecursiveSpecial() {
-        // Note: we need to check the parent's parent, because it might have been rewritten by
-        // bailout of some of its other arguments. If parent is special node, then its parent must
-        // be RCallSpecialNode
-        return propagateFullCallNeededException || (argumentIndex != NO_RECURSIVE_ARGUMENT_INDEX && getParent() != null && getParent().getParent() instanceof RCallSpecialNode);
-    }
-
     private RCallNode getRCallNode(RSyntaxNode[] newArguments) {
         return RCallNode.createCall(sourceSectionR, functionNode == null ? null : functionNode.getValueNode(), signature, newArguments);
     }
@@ -286,16 +278,18 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
         return getRCallNode(arguments);
     }
 
-    private void setArgumentIndex(int index) {
-        argumentIndex = index;
+    /**
+     * see {@link #propagateFullCallNeededException}.
+     */
+    public void setPropagateFullCallNeededException() {
+        propagateFullCallNeededException = true;
     }
 
     /**
-     * If set to {@code true} the special call will raise {@link FullCallNeededException} even when
-     * the parent is a special call.
+     * see {@link #callSpecialParent}.
      */
-    public void setPropagateFullCallNeededException(boolean flag) {
-        propagateFullCallNeededException = flag;
+    private void setCallSpecialParent(RCallSpecialNode call) {
+        callSpecialParent = call;
     }
 
     @Override
@@ -318,20 +312,4 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode
     public RSyntaxElement[] getSyntaxArguments() {
         return arguments == null ? new RSyntaxElement[]{RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "...", false)} : arguments;
     }
-
-    @SuppressWarnings("serial")
-    public static final class RecursiveSpecialBailout extends RuntimeException {
-        public final int argumentIndex;
-        public final Object rhsValue;
-
-        RecursiveSpecialBailout(int argumentIndex, Object rhsValue) {
-            this.argumentIndex = argumentIndex;
-            this.rhsValue = rhsValue;
-        }
-
-        @Override
-        public synchronized Throwable fillInStackTrace() {
-            return null;
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootWithBody.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootWithBody.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2736e10e5e517f3d2d9d73c1109e44cfdfdd3ba
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootWithBody.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime;
+
+import com.oracle.truffle.r.runtime.nodes.RNode;
+
+/**
+ * Used for testing.
+ */
+public interface RootWithBody {
+
+    RNode getBody();
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
index 8c434b5af633b287c8aed8345d2e8fe4b6625689..94d1d71fb49c3ac82b4b3f74a69a2f5fa3e18356 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
@@ -31,8 +31,6 @@ public class RExpression extends RListBase implements RAbstractVector {
 
     private static final RStringVector implicitClassHeader = RDataFactory.createStringVectorFromScalar(RType.Expression.getClazz());
 
-    public String elementNamePrefix;
-
     RExpression(Object[] data, int[] dims, RStringVector names) {
         super(data, dims, names);
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 770ebe2b4ec977c8fd227b52fcf946edeb8a4417..e8978bb9d46e9afe5b8e564249e6a48f9f668c07 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -4039,7 +4039,7 @@ attr(,"match.length")
 [1] -1
 
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_args.testArgs#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_args.testArgs#Output.IgnoreWhitespace#
 #{  f <- function(x=1, y) x + y; args(f); }
 function (x = 1, y)
 NULL
@@ -6139,12 +6139,12 @@ Error in as.vector(x, "expression") :
 #argv <- structure(list(x = 1), .Names = 'x');do.call('as.expression', argv)
 expression(1)
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction#Output.IgnoreWhitespace#
 #as.function(c(alist(a=1+14, b=foo(x),c=), quote(a+foo(c)*b)))
 function (a = 1 + 14, b = foo(x), c)
 a + foo(c) * b
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction#Output.IgnoreWhitespace#
 #f <- function() a+foo(c)*b; as.function(c(alist(a=1+14, b=foo(x),c=), body(f)))
 function (a = 1 + 14, b = foo(x), c)
 a + foo(c) * b