diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
index 92d043c445615d2a431604f7e0f7f12b965093ca..6f3c3bc9c082d8bd0b8362e9ead3982deed14382 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java
@@ -41,10 +41,11 @@ import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.AsVectorNodeGen.AsVectorInternalNodeGen.CastPairListNodeGen;
+import com.oracle.truffle.r.nodes.function.CallMatcherNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
 import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode;
-import com.oracle.truffle.r.nodes.function.UseMethodInternalNode;
+import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result;
 import com.oracle.truffle.r.nodes.unary.CastComplexNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
 import com.oracle.truffle.r.nodes.unary.CastExpressionNode;
@@ -77,7 +78,9 @@ public abstract class AsVector extends RBuiltinNode {
 
     @Child private AsVectorInternal internal = AsVectorInternalNodeGen.create();
     @Child private ClassHierarchyNode classHierarchy = ClassHierarchyNodeGen.create(false, false);
-    @Child private UseMethodInternalNode useMethod;
+
+    @Child private S3FunctionLookupNode lookup;
+    @Child private CallMatcherNode callMatcher;
 
     private final ConditionProfile hasClassProfile = ConditionProfile.createBinaryProfile();
 
@@ -98,16 +101,19 @@ public abstract class AsVector extends RBuiltinNode {
         // However, removing it causes unit test failures
         RStringVector clazz = classHierarchy.execute(x);
         if (hasClassProfile.profile(clazz != null)) {
-            if (useMethod == null) {
-                // Note: this dispatch takes care of factor, because there is as.vector.factor
-                // specialization in R
+            // Note: this dispatch takes care of factor, because there is as.vector.factor
+            // specialization in R
+            if (lookup == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                useMethod = insert(new UseMethodInternalNode("as.vector", SIGNATURE, false));
+                lookup = insert(S3FunctionLookupNode.create(false, false));
             }
-            try {
-                return useMethod.execute(frame, clazz, new Object[]{x, mode});
-            } catch (S3FunctionLookupNode.NoGenericMethodException e) {
-                // fallthrough
+            Result lookupResult = lookup.execute(frame, "as.vector", clazz, null, frame.materialize(), null);
+            if (lookupResult != null) {
+                if (callMatcher == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    callMatcher = insert(CallMatcherNode.create(false));
+                }
+                return callMatcher.execute(frame, SIGNATURE, new Object[]{x, mode}, lookupResult.function, lookupResult.targetFunctionName, lookupResult.createS3Args(frame));
             }
         }
         return internal.execute(x, mode);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
index 0a95c508e5ae397f7717df4e96528108cb1d0c27..13294d4f362ab562c0db9a44cb1426995eaca939 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java
@@ -43,8 +43,9 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAt
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.function.CallMatcherNode;
 import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode;
-import com.oracle.truffle.r.nodes.function.UseMethodInternalNode;
+import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result;
 import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode;
 import com.oracle.truffle.r.nodes.unary.CastComplexNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
@@ -97,10 +98,12 @@ public abstract class Bind extends RBaseNode {
     public abstract Object execute(VirtualFrame frame, int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, int precedence);
 
     @Child private CastToVectorNode castVector;
-    @Child private UseMethodInternalNode dcn;
     @Child private CastLogicalNode castLogical;
     @Child private GetDimAttributeNode getDimsNode;
 
+    @Child private S3FunctionLookupNode lookup;
+    @Child private CallMatcherNode callMatcher;
+
     private final BindType type;
 
     private final ConditionProfile nullNamesProfile = ConditionProfile.createBinaryProfile();
@@ -162,15 +165,19 @@ public abstract class Bind extends RBaseNode {
 
     @Specialization(guards = {"args.length > 0", "isDataFrame(args)"})
     protected Object allDataFrame(VirtualFrame frame, int deparseLevel, @SuppressWarnings("unused") Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) {
-        if (dcn == null) {
+        if (lookup == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            dcn = insert(new UseMethodInternalNode(type.toString(), SIGNATURE, false));
+            lookup = insert(S3FunctionLookupNode.create(false, false));
         }
-        try {
-            return dcn.execute(frame, DATA_FRAME_CLASS, new Object[]{deparseLevel, promiseArgs});
-        } catch (S3FunctionLookupNode.NoGenericMethodException e) {
+        Result lookupResult = lookup.execute(frame, type.toString(), DATA_FRAME_CLASS, null, frame.materialize(), null);
+        if (lookupResult == null) {
             throw RInternalError.shouldNotReachHere();
         }
+        if (callMatcher == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            callMatcher = insert(CallMatcherNode.create(false));
+        }
+        return callMatcher.execute(frame, SIGNATURE, new Object[]{deparseLevel, promiseArgs}, lookupResult.function, lookupResult.targetFunctionName, lookupResult.createS3Args(frame));
     }
 
     private Object bindInternal(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast, SetDimAttributeNode setDimNode,
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
index c4a29770e6ed51657735ce8b9077e9e4990673ba..c492da931b26adedf73a7520833fdd76fd63ed4d 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CRC64.java
@@ -52,13 +52,13 @@ public abstract class CRC64 extends RBuiltinNode {
         bytes = crc64(bytes);
         long l = 0;
         for (int i = 0; i < bytes.length; i++) {
-            l += ((long) bytes[i] & 0xffL) << (8 * i);
+            l += (bytes[i] & 0xffL) << (8 * i);
         }
         return RDataFactory.createStringVector(Long.toHexString(l));
     }
 
     @TruffleBoundary
-    private byte[] crc64(byte[] bytes) {
+    private static byte[] crc64(byte[] bytes) {
         org.tukaani.xz.check.CRC64 crc = new org.tukaani.xz.check.CRC64();
         crc.update(bytes);
         return crc.finish();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
index 54ecf0b6dc9db4eaf3fcfd74062c55e6372bb18c..4cd34ed9f441d06c369bdfc1c72c98880a2d1d24 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
@@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.Frame;
@@ -89,21 +88,18 @@ public abstract class Lapply extends RBuiltinNode {
 
     private static final class ExtractElementInternal extends RSourceSectionNode implements RSyntaxCall {
 
-        protected ExtractElementInternal() {
+        @Child private ExtractVectorNode extractElementNode = ExtractVectorNodeGen.create(ElementAccessMode.SUBSCRIPT, false);
+        private final FrameSlot vectorSlot;
+        private final FrameSlot indexSlot;
+
+        protected ExtractElementInternal(FrameSlot vectorSlot, FrameSlot indexSlot) {
             super(RSyntaxNode.LAZY_DEPARSE);
+            this.vectorSlot = vectorSlot;
+            this.indexSlot = indexSlot;
         }
 
-        @Child private ExtractVectorNode extractElementNode = ExtractVectorNodeGen.create(ElementAccessMode.SUBSCRIPT, false);
-        @CompilationFinal private FrameSlot vectorSlot;
-        @CompilationFinal private FrameSlot indexSlot;
-
         @Override
         public Object execute(VirtualFrame frame) {
-            if (vectorSlot == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                vectorSlot = frame.getFrameDescriptor().findFrameSlot("X");
-                indexSlot = frame.getFrameDescriptor().findFrameSlot("i");
-            }
             try {
                 return extractElementNode.apply(frame, frame.getObject(vectorSlot), new Object[]{frame.getInt(indexSlot)}, RRuntime.LOGICAL_TRUE, RRuntime.LOGICAL_TRUE);
             } catch (FrameSlotTypeException e) {
@@ -149,8 +145,8 @@ public abstract class Lapply extends RBuiltinNode {
                         @Cached("createVectorSlot(frame)") FrameSlot vectorSlot, //
                         @Cached("create()") RLengthNode lengthNode, //
                         @Cached("createCountingProfile()") LoopConditionProfile loop, //
-                        @Cached("createCallNode()") RCallNode firstCallNode, //
-                        @Cached("createCallNode()") RCallNode callNode) {
+                        @Cached("createCallNode(vectorSlot, indexSlot)") RCallNode firstCallNode, //
+                        @Cached("createCallNode(vectorSlot, indexSlot)") RCallNode callNode) {
             // TODO: R switches to double if x.getLength() is greater than 2^31-1
             frame.setObject(vectorSlot, vector);
             int length = lengthNode.executeInteger(frame, vector);
@@ -171,10 +167,10 @@ public abstract class Lapply extends RBuiltinNode {
         /**
          * Creates the {@link RCallNode} for this target and {@code varArgs}.
          */
-        protected RCallNode createCallNode() {
+        protected RCallNode createCallNode(FrameSlot vectorSlot, FrameSlot indexSlot) {
             CompilerAsserts.neverPartOfCompilation();
 
-            ExtractElementInternal element = new ExtractElementInternal();
+            ExtractElementInternal element = new ExtractElementInternal(vectorSlot, indexSlot);
             ReadVariableNode readArgs = ReadVariableNode.createSilent(ArgumentsSignature.VARARG_NAME, RType.Any);
 
             return RCallNode.createCall(createCallSourceSection(), ReadVariableNode.create("FUN"), ArgumentsSignature.get(null, "..."), element, readArgs);
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 da099379b27d2dde035be4f0c2cd48c14c135918..cf0585f4b13e7078466524a68b3ae09b79fbbb28 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
@@ -63,7 +63,7 @@ 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.data.RTypedValue;
-import com.oracle.truffle.r.runtime.data.RTypes;
+import com.oracle.truffle.r.runtime.data.RTypesFlatLayout;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -85,7 +85,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
  */
 public final class ReadVariableNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxLookup {
 
-    private static final int MAX_INVALIDATION_COUNT = 3;
+    private static final int MAX_INVALIDATION_COUNT = 8;
 
     private enum ReadKind {
         Normal,
@@ -184,20 +184,22 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
 
         Object result;
         if (read == null) {
-            initializeRead(frame, variableFrame);
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            initializeRead(frame, variableFrame, false);
         }
         try {
             result = read.execute(frame, variableFrame);
         } catch (InvalidAssumptionException | LayoutChangedException | FrameSlotTypeException e) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             int iterations = 0;
             while (true) {
                 iterations++;
-                initializeRead(frame, variableFrame);
+                initializeRead(frame, variableFrame, true);
                 try {
                     result = read.execute(frame, variableFrame);
                 } catch (InvalidAssumptionException | LayoutChangedException | FrameSlotTypeException e2) {
                     if (iterations > 10) {
-                        throw new RInternalError("too many iterations during RVN initialization: " + identifier);
+                        throw new RInternalError("too many iterations during RVN initialization: " + identifier + " " + e2 + " " + read + " " + getRootNode());
                     }
                     continue;
                 }
@@ -217,10 +219,13 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
         return result;
     }
 
-    private void initializeRead(VirtualFrame frame, Frame variableFrame) {
-        CompilerDirectives.transferToInterpreterAndInvalidate();
-        read = initialize(frame, variableFrame);
-        needsCopying = kind == ReadKind.Copying && !(read instanceof Match || read instanceof DescriptorStableMatch);
+    private synchronized void initializeRead(VirtualFrame frame, Frame variableFrame, boolean invalidate) {
+        CompilerAsserts.neverPartOfCompilation();
+        // do nothing if another thread initialized in the meantime
+        if (invalidate || read == null) {
+            read = initialize(frame, variableFrame);
+            needsCopying = kind == ReadKind.Copying && !(read instanceof Match || read instanceof DescriptorStableMatch);
+        }
     }
 
     private static final class LayoutChangedException extends SlowPathException {
@@ -478,27 +483,52 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
     private final class LookupLevel extends DescriptorLevel {
 
         private final LookupResult lookup;
-        private final ValueProfile frameProfile = ValueProfile.createClassProfile();
         private final ConditionProfile nullValueProfile = kind == ReadKind.Silent ? null : ConditionProfile.createBinaryProfile();
 
         private LookupLevel(LookupResult lookup) {
             this.lookup = lookup;
+            assert !(lookup instanceof FrameAndSlotLookupResult);
         }
 
         @Override
         public Object execute(VirtualFrame frame) throws InvalidAssumptionException, LayoutChangedException, FrameSlotTypeException {
-            Object value;
-            if (lookup instanceof FrameAndSlotLookupResult) {
-                FrameAndSlotLookupResult frameAndSlotLookupResult = (FrameAndSlotLookupResult) lookup;
-                value = profiledGetValue(seenValueKinds, frameProfile.profile(frameAndSlotLookupResult.getFrame()), frameAndSlotLookupResult.getSlot());
-            } else {
-                value = lookup.getValue();
-            }
+            Object value = lookup.getValue();
             if (kind != ReadKind.Silent && nullValueProfile.profile(value == null)) {
                 throw RError.error(RError.SHOW_CALLER, mode == RType.Function ? RError.Message.UNKNOWN_FUNCTION : RError.Message.UNKNOWN_OBJECT, identifier);
             }
             return value;
         }
+
+        @Override
+        public String toString() {
+            return "<LU>";
+        }
+    }
+
+    private final class FrameAndSlotLookupLevel extends DescriptorLevel {
+
+        private final FrameAndSlotLookupResult lookup;
+        private final ValueProfile frameProfile = ValueProfile.createClassProfile();
+        private final ConditionProfile isNullProfile = ConditionProfile.createBinaryProfile();
+
+        private FrameAndSlotLookupLevel(FrameAndSlotLookupResult lookup) {
+            this.lookup = lookup;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) throws InvalidAssumptionException, LayoutChangedException, FrameSlotTypeException {
+            Object value = profiledGetValue(seenValueKinds, frameProfile.profile(lookup.getFrame()), lookup.getSlot());
+            if (!checkType(frame, value, isNullProfile)) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                throw new LayoutChangedException();
+            }
+            return value;
+        }
+
+        @Override
+        public String toString() {
+            return "<FSLU>";
+        }
     }
 
     private FrameLevel initialize(VirtualFrame frame, Frame variableFrame) {
@@ -538,8 +568,14 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
                     evalPromiseSlowPathWithName(identifierAsString, frame, (RPromise) lookup.getValue());
                 }
                 if (lookup != null) {
-                    if (lookup.getValue() == null || checkTypeSlowPath(frame, lookup.getValue())) {
-                        return new LookupLevel(lookup);
+                    if (lookup instanceof FrameAndSlotLookupResult) {
+                        if (checkTypeSlowPath(frame, lookup.getValue())) {
+                            return new FrameAndSlotLookupLevel((FrameAndSlotLookupResult) lookup);
+                        }
+                    } else {
+                        if (lookup.getValue() == null || checkTypeSlowPath(frame, lookup.getValue())) {
+                            return new LookupLevel(lookup);
+                        }
                     }
                 }
             } catch (InvalidAssumptionException e) {
@@ -880,7 +916,7 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta
 /*
  * This is RRuntime.checkType in the node form.
  */
-@TypeSystemReference(RTypes.class)
+@TypeSystemReference(RTypesFlatLayout.class)
 abstract class CheckTypeNode extends RBaseNode {
 
     public abstract boolean executeBoolean(Object o);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
index 00fd37061cd9548111df37b17ddf621dea0401ca..3a3f0fe6d7477ce2aa7426dd4c7ae506f7867b8e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java
@@ -23,7 +23,6 @@
 package com.oracle.truffle.r.nodes.binary;
 
 import com.oracle.truffle.api.CompilerAsserts;
-import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
@@ -65,26 +64,19 @@ public abstract class BinaryBooleanScalarNode extends RBuiltinNode {
 
     BinaryBooleanScalarNode(BooleanOperationFactory factory) {
         this.booleanLogic = factory.createOperation();
+        logic = new BinaryMapBooleanFunctionNode(booleanLogic);
+        leftCast = LogicalScalarCastNodeGen.create(booleanLogic.opName(), "x", logic.getLeftNACheck());
+        leftBox = BoxPrimitiveNodeGen.create();
+        rightCast = LogicalScalarCastNodeGen.create(booleanLogic.opName(), "y", logic.getRightNACheck());
+        rightBox = BoxPrimitiveNodeGen.create();
+        promiseHelper = new PromiseCheckHelperNode();
     }
 
     @Specialization
     protected byte binary(VirtualFrame frame, Object leftValue, Object rightValue) {
-        if (leftCast == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            logic = insert(new BinaryMapBooleanFunctionNode(booleanLogic));
-            leftCast = insert(LogicalScalarCastNodeGen.create(booleanLogic.opName(), "x", logic.getLeftNACheck()));
-            leftBox = insert(BoxPrimitiveNodeGen.create());
-        }
         byte left = leftCast.executeCast(leftBox.execute(leftValue));
         if (profile.profile(logic.requiresRightOperand(left))) {
-            if (rightCast == null) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                rightCast = insert(LogicalScalarCastNodeGen.create(booleanLogic.opName(), "y", logic.getRightNACheck()));
-                rightBox = insert(BoxPrimitiveNodeGen.create());
-                promiseHelper = insert(new PromiseCheckHelperNode());
-            }
-            byte right = rightCast.executeCast(rightBox.execute(promiseHelper.checkEvaluate(frame, rightValue)));
-            return logic.applyLogical(left, right);
+            return logic.applyLogical(left, rightCast.executeCast(rightBox.execute(promiseHelper.checkEvaluate(frame, rightValue))));
         }
         return left;
     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java
index 3e3347bf7972c9421593be2388be054e9a88a0bc..6100faa0f41002be34f10714130b93693fffade9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentStatePush.java
@@ -24,25 +24,33 @@ package com.oracle.truffle.r.nodes.function;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNode;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RShareable;
+import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 
 /**
  * A {@link ArgumentStatePush} is used to bump up state transition for function arguments.
  */
+@TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 public abstract class ArgumentStatePush extends Node {
 
     public abstract void executeObject(VirtualFrame frame, Object shareable);
 
+    @Child private WriteLocalFrameVariableNode write;
+
     private final ConditionProfile isRefCountUpdateable = ConditionProfile.createBinaryProfile();
 
     private final int index;
@@ -57,76 +65,59 @@ public abstract class ArgumentStatePush extends Node {
         this.index = index;
     }
 
-    public boolean refCounted() {
-        return mask > 0;
+    protected int createWriteArgMask(VirtualFrame frame, RShareable shareable) {
+        if (shareable instanceof RAbstractContainer) {
+            if (shareable instanceof RLanguage || ((RAbstractContainer) shareable).getLength() < REF_COUNT_SIZE_THRESHOLD) {
+                // don't decrement ref count for small objects or language objects- this
+                // is pretty conservative and can be further finessed
+                return -1;
+            }
+        }
+        RFunction fun = RArguments.getFunction(frame);
+        if (fun == null) {
+            return -1;
+        }
+        Object root = fun.getRootNode();
+        if (!(root instanceof FunctionDefinitionNode)) {
+            // root is RBuiltinRootNode
+            return -1;
+        }
+        FunctionDefinitionNode fdn = (FunctionDefinitionNode) root;
+        PostProcessArgumentsNode postProcessNode = fdn.getArgPostProcess();
+        if (postProcessNode == null) {
+            // arguments to this function are not to be reference counted
+            return -1;
+        }
+        if (!postProcessNode.updateBits(index)) {
+            // this will fail if the index is too big
+            return -1;
+        }
+        return 1 << index;
     }
 
     @Specialization
-    public void transitionState(VirtualFrame frame, RShareable shareable) {
+    public void transitionState(VirtualFrame frame, RSharingAttributeStorage shareable,
+                    @Cached("createWriteArgMask(frame, shareable)") int writeArgMask) {
         if (isRefCountUpdateable.profile(!shareable.isSharedPermanent())) {
             shareable.incRefCount();
-            if (!FastROptions.RefCountIncrementOnly.getBooleanValue()) {
-                if (mask == 0) {
+            if (writeArgMask != -1 && !FastROptions.RefCountIncrementOnly.getBooleanValue()) {
+                if (write == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    if (shareable instanceof RAbstractContainer) {
-                        if (shareable instanceof RLanguage || ((RAbstractContainer) shareable).getLength() < REF_COUNT_SIZE_THRESHOLD) {
-                            // don't decrement ref count for small objects or language objects- this
-                            // is
-                            // pretty conservative and can be further finessed
-                            mask = -1;
-                            return;
-                        }
-                    }
-                    RFunction fun = RArguments.getFunction(frame);
-                    if (fun == null) {
-                        mask = -1;
-                        return;
-                    }
-                    Object root = fun.getRootNode();
-                    if (!(root instanceof FunctionDefinitionNode)) {
-                        // root is RBuiltinRootNode
-                        mask = -1;
-                        return;
-                    }
-                    FunctionDefinitionNode fdn = (FunctionDefinitionNode) root;
-                    PostProcessArgumentsNode postProcessNode = fdn.getArgPostProcess();
-                    if (postProcessNode == null) {
-                        // arguments to this function are not to be reference counted
-                        mask = -1;
-                        return;
-                    }
-                    // this is needed for when FunctionDefinitionNode is split by the Truffle
-                    // runtime
-                    postProcessNode = postProcessNode.getActualNode();
-                    if (index >= Math.min(postProcessNode.getLength(), MAX_COUNTED_ARGS)) {
-                        mask = -1;
-                        return;
-                    }
-                    mask = 1 << index;
-                    int transArgsBitSet = postProcessNode.transArgsBitSet;
-                    postProcessNode.transArgsBitSet = transArgsBitSet | mask;
-                    writeArgNode = insert(WriteLocalFrameVariableNode.createForRefCount(Integer.valueOf(mask)));
-                }
-                if (mask != -1) {
-                    writeArgNode.execute(frame, shareable);
+                    write = insert(WriteLocalFrameVariableNode.createForRefCount(Integer.valueOf(writeArgMask)));
                 }
+                write.execute(frame, shareable);
             }
         }
     }
 
+    @Specialization
+    public void transitionState(RShareable shareable) {
+        throw RInternalError.shouldNotReachHere("unexpected RShareable that is not RSharingAttributeStorage: " + shareable.getClass());
+    }
+
     @Specialization(guards = "!isShareable(o)")
-    public void transitionStateNonShareable(VirtualFrame frame, @SuppressWarnings("unused") Object o) {
-        if (mask > 0) {
-            // this argument used to be reference counted but is no longer
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            RFunction fun = RArguments.getFunction(frame);
-            assert fun != null;
-            FunctionDefinitionNode fdn = (FunctionDefinitionNode) fun.getRootNode();
-            assert fdn != null;
-            int transArgsBitSet = fdn.getArgPostProcess().transArgsBitSet;
-            fdn.getArgPostProcess().transArgsBitSet = transArgsBitSet & (~mask);
-            mask = -1;
-        }
+    public void transitionStateNonShareable(@SuppressWarnings("unused") Object o) {
+        // do nothing
     }
 
     protected boolean isShareable(Object o) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java
index 6359e94caa2fbf0e94bdf95af98c5b7dc4633ace..818244e964bd14a74c07476e39b4bb09d00706fa 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallArgumentsNode.java
@@ -161,8 +161,18 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum
         return Arguments.create(values, ArgumentsSignature.get(newNames));
     }
 
-    private ArgumentsSignature cachedVarArgsSignature;
-    private ArgumentsSignature cachedResultSignature;
+    private static final class CachedSignature {
+        private final ArgumentsSignature signature;
+        private final ArgumentsSignature resultSignature;
+
+        protected CachedSignature(ArgumentsSignature signature, ArgumentsSignature resultSignature) {
+            this.signature = signature;
+            this.resultSignature = resultSignature;
+        }
+    }
+
+    private CachedSignature cachedVarArgsSignature;
+
     private final BranchProfile regenerateSignatureProfile = BranchProfile.create();
 
     public ArgumentsSignature flattenNames(RArgsValuesAndNames varArgs) {
@@ -170,15 +180,15 @@ public final class CallArgumentsNode extends RBaseNode implements UnmatchedArgum
             return signature;
         }
         ArgumentsSignature varArgsSignature = varArgs.getSignature();
-        if (cachedVarArgsSignature == null) {
+        CachedSignature cached = cachedVarArgsSignature;
+        if (cached == null) {
             CompilerDirectives.transferToInterpreter();
         }
-        if (varArgsSignature == cachedVarArgsSignature) {
-            return cachedResultSignature;
+        if (cached == null || varArgsSignature != cached.signature) {
+            regenerateSignatureProfile.enter();
+            cachedVarArgsSignature = cached = new CachedSignature(varArgsSignature, flattenNamesInternal(varArgsSignature));
         }
-        regenerateSignatureProfile.enter();
-        cachedVarArgsSignature = varArgsSignature;
-        return cachedResultSignature = flattenNamesInternal(varArgsSignature);
+        return cached.resultSignature;
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
index 9454d1b46b985707c8c836d1c714a9b1b86936e3..e034cfa67da52aab6d8a18ab88da0b95344e6a95 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java
@@ -60,7 +60,7 @@ public abstract class CallMatcherNode extends RBaseNode {
     private static final int MAX_CACHE_DEPTH = 3;
 
     public static CallMatcherNode create(boolean argsAreEvaluated) {
-        return new CallMatcherUninitializedNode(argsAreEvaluated);
+        return new CallMatcherUninitializedNode(argsAreEvaluated, 0);
     }
 
     public abstract Object execute(VirtualFrame frame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments, RFunction function, String functionName, DispatchArgs dispatchArgs);
@@ -151,19 +151,20 @@ public abstract class CallMatcherNode extends RBaseNode {
 
     @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class CallMatcherUninitializedNode extends CallMatcherNode {
-        CallMatcherUninitializedNode(boolean argsAreEvaluated) {
+        CallMatcherUninitializedNode(boolean argsAreEvaluated, int depth) {
             super(argsAreEvaluated);
+            this.depth = depth;
         }
 
-        private int depth;
+        private final int depth;
 
         @Override
         public Object execute(VirtualFrame frame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments, RFunction function, String functionName, DispatchArgs dispatchArgs) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            if (++depth > MAX_CACHE_DEPTH) {
+            if (depth > MAX_CACHE_DEPTH) {
                 return replace(new CallMatcherGenericNode(argsAreEvaluated)).execute(frame, suppliedSignature, suppliedArguments, function, functionName, dispatchArgs);
             } else {
-                CallMatcherCachedNode cachedNode = replace(specialize(suppliedSignature, suppliedArguments, function, this));
+                CallMatcherCachedNode cachedNode = replace(specialize(suppliedSignature, suppliedArguments, function, new CallMatcherUninitializedNode(argsAreEvaluated, depth + 1)));
                 // for splitting if necessary
                 if (cachedNode.call != null && RCallNode.needsSplitting(function.getTarget())) {
                     cachedNode.call.getCallNode().cloneCallTarget();
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 4a2c89ad48a62fc5debd7c6be8f4bb3ca2864f8e..2e3030709b306ecc445d7a5bdf376c11bf1ea4f5 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
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.frame.FrameDescriptor;
 import com.oracle.truffle.api.frame.FrameSlot;
+import com.oracle.truffle.api.frame.FrameSlotKind;
 import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.Node;
@@ -101,24 +102,13 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
     private final BranchProfile breakProfile = BranchProfile.create();
     private final BranchProfile nextProfile = BranchProfile.create();
 
-    @CompilationFinal private BranchProfile invalidateFrameSlotProfile;
-    // S3/S4 slots
-    @Child private FrameSlotNode dotGenericSlot;
-    @Child private FrameSlotNode dotMethodSlot;
-    // S3 slots
-    @Child private FrameSlotNode dotClassSlot;
-    @Child private FrameSlotNode dotGenericCallEnvSlot;
-    @Child private FrameSlotNode dotGenericCallDefSlot;
-    @Child private FrameSlotNode dotGroupSlot;
-    // S4 slots
-    @Child private FrameSlotNode dotDefinedSlot;
-    @Child private FrameSlotNode dotTargetSlot;
-    @Child private FrameSlotNode dotMethodsSlot;
-
     @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
     @Child private PostProcessArgumentsNode argPostProcess;
 
+    @Child private SetupS3ArgsNode setupS3Args;
+    @Child private SetupS4ArgsNode setupS4Args;
+
     private final boolean needsSplitting;
 
     @CompilationFinal private boolean containsDispatch;
@@ -317,55 +307,88 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         }
     }
 
+    private abstract static class SetupDispatchNode extends Node {
+        // S3/S4 slots
+        private final FrameSlot dotGenericSlot;
+        private final FrameSlot dotMethodSlot;
+
+        final BranchProfile invalidateFrameSlotProfile = BranchProfile.create();
+
+        SetupDispatchNode(FrameDescriptor frameDescriptor) {
+            dotGenericSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC, FrameSlotKind.Object);
+            dotMethodSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHOD, FrameSlotKind.Object);
+        }
+
+        void execute(VirtualFrame frame, DispatchArgs args) {
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericSlot, args.generic, false, invalidateFrameSlotProfile);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodSlot, args.method, false, invalidateFrameSlotProfile);
+        }
+    }
+
+    private static final class SetupS3ArgsNode extends SetupDispatchNode {
+        // S3 slots
+        private final FrameSlot dotClassSlot;
+        private final FrameSlot dotGenericCallEnvSlot;
+        private final FrameSlot dotGenericCallDefSlot;
+        private final FrameSlot dotGroupSlot;
+
+        SetupS3ArgsNode(FrameDescriptor frameDescriptor) {
+            super(frameDescriptor);
+            dotClassSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_CLASS, FrameSlotKind.Object);
+            dotGenericCallEnvSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_CALL_ENV, FrameSlotKind.Object);
+            dotGenericCallDefSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_DEF_ENV, FrameSlotKind.Object);
+            dotGroupSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GROUP, FrameSlotKind.Object);
+        }
+
+        void execute(VirtualFrame frame, S3Args args) {
+            super.execute(frame, args);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotClassSlot, args.clazz, false, invalidateFrameSlotProfile);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallEnvSlot, args.callEnv, false, invalidateFrameSlotProfile);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallDefSlot, args.defEnv, false, invalidateFrameSlotProfile);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGroupSlot, args.group, false, invalidateFrameSlotProfile);
+        }
+    }
+
+    private static final class SetupS4ArgsNode extends SetupDispatchNode {
+        // S4 slots
+        private final FrameSlot dotDefinedSlot;
+        private final FrameSlot dotTargetSlot;
+        private final FrameSlot dotMethodsSlot;
+
+        SetupS4ArgsNode(FrameDescriptor frameDescriptor) {
+            super(frameDescriptor);
+            dotDefinedSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_DEFINED, FrameSlotKind.Object);
+            dotTargetSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_TARGET, FrameSlotKind.Object);
+            dotMethodsSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHODS, FrameSlotKind.Object);
+        }
+
+        void execute(VirtualFrame frame, S4Args args) {
+            super.execute(frame, args);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotDefinedSlot, args.defined, false, invalidateFrameSlotProfile);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotTargetSlot, args.target, false, invalidateFrameSlotProfile);
+            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodsSlot, args.methods, false, invalidateFrameSlotProfile);
+        }
+    }
+
     private void setupDispatchSlots(VirtualFrame frame) {
         DispatchArgs dispatchArgs = RArguments.getDispatchArgs(frame);
         if (dispatchArgs == null) {
             return;
         }
-        if (dotGenericSlot == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            assert invalidateFrameSlotProfile == null && dotMethodSlot == null;
-            invalidateFrameSlotProfile = BranchProfile.create();
-            FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
-
-            dotGenericSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GENERIC, true));
-            dotMethodSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_METHOD, true));
-        }
-        FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericSlot.executeFrameSlot(frame), dispatchArgs.generic, false, invalidateFrameSlotProfile);
-        FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodSlot.executeFrameSlot(frame), dispatchArgs.method, false, invalidateFrameSlotProfile);
-
         if (dispatchArgs instanceof S3Args) {
             S3Args s3Args = (S3Args) dispatchArgs;
-            if (dotClassSlot == null) {
+            if (setupS3Args == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                assert dotGenericCallEnvSlot == null && dotGenericCallDefSlot == null && dotGroupSlot == null;
-                invalidateFrameSlotProfile = BranchProfile.create();
-                FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
-
-                dotClassSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_CLASS, true));
-                dotGenericCallEnvSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GENERIC_CALL_ENV, true));
-                dotGenericCallDefSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GENERIC_DEF_ENV, true));
-                dotGroupSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_GROUP, true));
+                setupS3Args = insert(new SetupS3ArgsNode(frame.getFrameDescriptor()));
             }
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotClassSlot.executeFrameSlot(frame), s3Args.clazz, false, invalidateFrameSlotProfile);
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallEnvSlot.executeFrameSlot(frame), s3Args.callEnv, false, invalidateFrameSlotProfile);
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallDefSlot.executeFrameSlot(frame), s3Args.defEnv, false, invalidateFrameSlotProfile);
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGroupSlot.executeFrameSlot(frame), s3Args.group, false, invalidateFrameSlotProfile);
+            setupS3Args.execute(frame, s3Args);
         } else {
             S4Args s4Args = (S4Args) dispatchArgs;
-            if (dotDefinedSlot == null) {
+            if (setupS4Args == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                assert dotTargetSlot == null && dotMethodsSlot == null;
-                invalidateFrameSlotProfile = BranchProfile.create();
-                FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
-
-                dotDefinedSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_DEFINED, true));
-                dotTargetSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_TARGET, true));
-                dotMethodsSlot = insert(FrameSlotNode.createInitialized(frameDescriptor, RRuntime.R_DOT_METHODS, true));
+                setupS4Args = insert(new SetupS4ArgsNode(frame.getFrameDescriptor()));
             }
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotDefinedSlot.executeFrameSlot(frame), s4Args.defined, false, invalidateFrameSlotProfile);
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotTargetSlot.executeFrameSlot(frame), s4Args.target, false, invalidateFrameSlotProfile);
-            FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodsSlot.executeFrameSlot(frame), s4Args.methods, false, invalidateFrameSlotProfile);
+            setupS4Args.execute(frame, s4Args);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java
index 70c054c22da7929dfaac6ae718dd7b1af33e3650..e808377fefc5bedf97ad147c5d5950c6cfbd272a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PostProcessArgumentsNode.java
@@ -22,13 +22,11 @@
  */
 package com.oracle.truffle.r.nodes.function;
 
-import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
-import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.utilities.AssumedValue;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RShareable;
@@ -41,28 +39,20 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 public final class PostProcessArgumentsNode extends RNode {
 
     @Children private final LocalReadVariableNode[] sequence;
-    @Child private PostProcessArgumentsNode nextOptPostProccessArgNode;
-    @CompilationFinal int transArgsBitSet;
 
-    // the first time this node is cloned (via FunctionDefinitionNode) it's from the trufflerizer -
-    // in this case we should not create the node chain chain in the clone operation (below) at the
-    // reference count meta data needs to be associated with this node and not its clone
-    @CompilationFinal private boolean createClone;
+    // stays the same during cloning
+    private final AssumedValue<Integer> transArgsBitSet;
+
+    private final ConditionProfile isNonNull = ConditionProfile.createBinaryProfile();
     private final ConditionProfile isRefCountUpdateable = ConditionProfile.createBinaryProfile();
 
-    private PostProcessArgumentsNode(LocalReadVariableNode[] sequence) {
-        this.sequence = sequence;
-        this.createClone = false;
-        this.transArgsBitSet = 0;
+    private PostProcessArgumentsNode(int length) {
+        this.sequence = new LocalReadVariableNode[Math.min(length, ArgumentStatePush.MAX_COUNTED_ARGS)];
+        this.transArgsBitSet = new AssumedValue<>("PostProcessArgumentsNode.transArgsBitSet", 0);
     }
 
     public static PostProcessArgumentsNode create(int length) {
-        int maxLength = Math.min(length, ArgumentStatePush.MAX_COUNTED_ARGS);
-        LocalReadVariableNode[] argReadNodes = new LocalReadVariableNode[maxLength];
-        for (int i = 0; i < maxLength; i++) {
-            argReadNodes[i] = LocalReadVariableNode.create(Integer.valueOf(1 << i), false);
-        }
-        return new PostProcessArgumentsNode(argReadNodes);
+        return new PostProcessArgumentsNode(length);
     }
 
     public int getLength() {
@@ -72,20 +62,20 @@ public final class PostProcessArgumentsNode extends RNode {
     @Override
     @ExplodeLoop
     public Object execute(VirtualFrame frame) {
-        if (transArgsBitSet > 0) {
+        int bits = transArgsBitSet.get();
+        if (bits != 0) {
             for (int i = 0; i < sequence.length; i++) {
                 int mask = 1 << i;
-                if ((transArgsBitSet & mask) == mask) {
-                    RShareable s = (RShareable) sequence[i].execute(frame);
-                    if (s == null) {
-                        // it happens rarely in compiled code, but if it does happen, stop
-                        // decrementing reference counts
+                if ((bits & mask) != 0) {
+                    if (sequence[i] == null) {
                         CompilerDirectives.transferToInterpreterAndInvalidate();
-                        transArgsBitSet = ArgumentStatePush.INVALID_INDEX;
-                        break;
+                        sequence[i] = insert(LocalReadVariableNode.create(Integer.valueOf(mask), false));
                     }
-                    if (isRefCountUpdateable.profile(!s.isSharedPermanent())) {
-                        s.decRefCount();
+                    RShareable s = (RShareable) sequence[i].execute(frame);
+                    if (isNonNull.profile(s != null)) {
+                        if (isRefCountUpdateable.profile(!s.isSharedPermanent())) {
+                            s.decRefCount();
+                        }
                     }
                 }
             }
@@ -93,38 +83,15 @@ public final class PostProcessArgumentsNode extends RNode {
         return RNull.instance;
     }
 
-    @Override
-    public Node deepCopy() {
-        CompilerAsserts.neverPartOfCompilation();
-        if (createClone) {
-            return deepCopyUnconditional();
-        } else {
-            this.createClone = true;
-            return this;
-        }
-    }
-
-    /*
-     * Deep copies are also made from other places than the trufflerizer, in which case we need to
-     * always create the node chain.
-     */
-    private PostProcessArgumentsNode deepCopyUnconditional() {
-        CompilerAsserts.neverPartOfCompilation();
-        PostProcessArgumentsNode copy = (PostProcessArgumentsNode) super.deepCopy();
-        nextOptPostProccessArgNode = insert(copy);
-        return copy;
-
-    }
-
-    PostProcessArgumentsNode getActualNode() {
-        CompilerAsserts.neverPartOfCompilation();
-        if (nextOptPostProccessArgNode == null) {
-            return this;
-        } else {
-            PostProcessArgumentsNode nextNode = nextOptPostProccessArgNode.getActualNode();
-            // shorten up the lookup chain
-            nextOptPostProccessArgNode = insert(nextNode);
-            return nextNode;
+    public boolean updateBits(int index) {
+        if (index < sequence.length) {
+            int bits = transArgsBitSet.get();
+            int newBits = bits | (1 << index);
+            if (newBits != bits) {
+                transArgsBitSet.set(newBits);
+            }
+            return true;
         }
+        return false;
     }
 }
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 c46789e565ff14114ae83507b1e84a267fab3d1d..e9a22756634aa1683cf6ee0403f0649c818f0869 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
@@ -409,8 +409,17 @@ public abstract class PromiseNode extends RNode {
         private final ConditionProfile argsValueAndNamesProfile = ConditionProfile.createBinaryProfile();
         private final ConditionProfile containsVarargProfile = ConditionProfile.createBinaryProfile();
 
-        @CompilationFinal ArgumentsSignature cachedVarArgSignature;
-        @CompilationFinal ArgumentsSignature cachedResultSignature;
+        private static final class Cache {
+            private final ArgumentsSignature signature;
+            private final ArgumentsSignature result;
+
+            protected Cache(ArgumentsSignature signature, ArgumentsSignature result) {
+                this.signature = signature;
+                this.result = result;
+            }
+        }
+
+        @CompilationFinal private Cache varArgsCache;
 
         InlineVarArgsNode(RNode[] nodes, ArgumentsSignature signature) {
             this.varargs = nodes;
@@ -455,13 +464,20 @@ public abstract class PromiseNode extends RNode {
                 if (evaluatedArgs.length == 1) {
                     finalSignature = ((RArgsValuesAndNames) evaluatedArgs[0]).getSignature();
                 } else {
-                    if (cachedVarArgSignature == ArgumentsSignature.INVALID_SIGNATURE) {
+                    Cache cache = varArgsCache;
+                    if (cache == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        finalSignature = createSignature(evaluatedArgs, flattenedArgs.length);
+                        varArgsCache = new Cache(varArgSignature, finalSignature);
+                    } else if (cache.signature == ArgumentsSignature.INVALID_SIGNATURE) {
                         finalSignature = createSignature(evaluatedArgs, flattenedArgs.length);
-                    } else if (varArgSignature == cachedVarArgSignature) {
-                        finalSignature = cachedResultSignature;
+                    } else if (varArgSignature == cache.signature) {
+                        finalSignature = cache.result;
                     } else {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        // fallback to the generic case
                         finalSignature = createSignature(evaluatedArgs, flattenedArgs.length);
-                        cachedVarArgSignature = cachedVarArgSignature == null ? finalSignature : ArgumentsSignature.INVALID_SIGNATURE;
+                        varArgsCache = new Cache(ArgumentsSignature.INVALID_SIGNATURE, null);
                     }
                 }
                 return new RArgsValuesAndNames(flattenedArgs, finalSignature);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
index d202fe1015cfe2a332ff77da078972284f3fecf1..4e172dbb8c5580e2dffd05863735790ea208d5b7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.NodeChild;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
+import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
@@ -55,14 +56,12 @@ import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
-import com.oracle.truffle.r.nodes.access.FrameSlotNode;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinRootNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode;
 import com.oracle.truffle.r.nodes.function.RCallNodeGen.FunctionDispatchNodeGen;
-import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.NoGenericMethodException;
 import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result;
 import com.oracle.truffle.r.nodes.function.call.CallRFunctionNode;
 import com.oracle.truffle.r.nodes.function.call.PrepareArguments;
@@ -234,11 +233,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
     }
 
     protected FunctionDispatch createUninitializedCall() {
-        return FunctionDispatchNodeGen.create(this, null, explicitArgs == null ? false : true);
+        return FunctionDispatchNodeGen.create(this, explicitArgs != null, null);
     }
 
     protected FunctionDispatch createUninitializedExplicitCall() {
-        return FunctionDispatchNodeGen.create(this, null, true);
+        return FunctionDispatchNodeGen.create(this, true, null);
     }
 
     /**
@@ -284,7 +283,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                     @Cached("createBinaryProfile()") ConditionProfile resultIsBuiltinProfile) {
         RBuiltinDescriptor builtin = builtinProfile.profile(function.getRBuiltin());
         Object dispatchObject = dispatchArgument.execute(frame);
-        dispatchTempSlot.initialize(frame, dispatchObject, () -> internalDispatchCall = null);
+        FrameSlot slot = dispatchTempSlot.initialize(frame, dispatchObject);
         try {
             RStringVector type = classHierarchyNode.execute(dispatchObject);
             S3Args s3Args;
@@ -301,13 +300,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                 s3Args = null;
                 resultFunction = function;
             }
-            if (internalDispatchCall == null) {
+            if (internalDispatchCall == null || internalDispatchCall.tempFrameSlot != slot) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                internalDispatchCall = insert(FunctionDispatchNodeGen.create(this, new Object[]{dispatchTempSlot.getIdentifier()}, false));
+                internalDispatchCall = insert(FunctionDispatchNodeGen.create(this, false, slot));
             }
             return internalDispatchCall.execute(frame, resultFunction, lookupVarArgs(frame), s3Args, null);
         } finally {
-            dispatchTempSlot.cleanup(frame, dispatchObject);
+            TemporarySlotNode.cleanup(frame, dispatchObject, slot);
         }
     }
 
@@ -399,21 +398,13 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         RStringVector typeX = classHierarchyNodeX.execute(promiseHelperNode.checkEvaluate(frame, args[typeXIdx]));
         Result resultX = null;
         if (implicitTypeProfileX.profile(typeX != null)) {
-            try {
-                resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), null);
-            } catch (NoGenericMethodException e) {
-                // fall-through
-            }
+            resultX = dispatchLookupX.execute(frame, builtin.getName(), typeX, dispatch.getGroupGenericName(), frame.materialize(), null);
         }
         Result resultY = null;
         if (args.length > 1 && dispatch == RDispatch.OPS_GROUP_GENERIC) {
             RStringVector typeY = classHierarchyNodeY.execute(promiseHelperNode.checkEvaluate(frame, args[1]));
             if (implicitTypeProfileY.profile(typeY != null)) {
-                try {
-                    resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), null);
-                } catch (NoGenericMethodException e) {
-                    // fall-through
-                }
+                resultY = dispatchLookupY.execute(frame, builtin.getName(), typeY, dispatch.getGroupGenericName(), frame.materialize(), null);
             }
         }
 
@@ -548,11 +539,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         return getParentCallNode().getFunctionNode();
     }
 
-    public CallArgumentsNode createArguments(Object[] dispatchTempIdentifiers, boolean modeChange, boolean modeChangeAppliesToAll) {
+    public CallArgumentsNode createArguments(FrameSlot tempFrameSlot, boolean modeChange, boolean modeChangeAppliesToAll) {
         RNode[] args = new RNode[arguments.length];
         for (int i = 0; i < arguments.length; i++) {
-            if (dispatchTempIdentifiers != null && i < dispatchTempIdentifiers.length) {
-                args[i] = new GetTempNode(dispatchTempIdentifiers[i], arguments[i]);
+            if (tempFrameSlot != null && i == 0) {
+                args[i] = new GetTempNode(tempFrameSlot, arguments[i]);
             } else {
                 args[i] = arguments[i] == null ? null : RASTUtils.cloneNode(arguments[i].asRNode());
             }
@@ -570,7 +561,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
      */
     public static RNode createInternalCall(RCallNode internalCallArg, RFunction function) {
         CompilerAsserts.neverPartOfCompilation();
-        return new InternalNode(FunctionDispatchNodeGen.create(internalCallArg, null, false), function, internalCallArg.lookupVarArgs != null);
+        return new InternalNode(FunctionDispatchNodeGen.create(internalCallArg, false, null), function, internalCallArg.lookupVarArgs != null);
     }
 
     @NodeInfo(cost = NodeCost.NONE)
@@ -654,11 +645,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
 
     private static final class GetTempNode extends RNode {
 
-        @Child private FrameSlotNode slot;
+        private final FrameSlot slot;
         private final RSyntaxNode arg;
 
-        GetTempNode(Object identifier, RSyntaxNode arg) {
-            slot = FrameSlotNode.createTemp(identifier, false);
+        GetTempNode(FrameSlot slot, RSyntaxNode arg) {
+            this.slot = slot;
             this.arg = arg;
         }
 
@@ -670,7 +661,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         @Override
         public Object execute(VirtualFrame frame) {
             try {
-                return frame.getObject(slot.executeFrameSlot(frame));
+                return frame.getObject(slot);
             } catch (FrameSlotTypeException e) {
                 throw RInternalError.shouldNotReachHere();
             }
@@ -691,13 +682,14 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         protected static final int CACHE_SIZE = 4;
 
         private final RCallNode originalCall;
-        private final Object[] dispatchTempIdentifiers;
         private final boolean explicitArgs;
 
-        public FunctionDispatch(RCallNode originalCall, Object[] dispatchTempIdentifiers, boolean explicitArgs) {
+        private final FrameSlot tempFrameSlot;
+
+        public FunctionDispatch(RCallNode originalCall, boolean explicitArgs, FrameSlot tempFrameSlot) {
             this.originalCall = originalCall;
-            this.dispatchTempIdentifiers = dispatchTempIdentifiers;
             this.explicitArgs = explicitArgs;
+            this.tempFrameSlot = tempFrameSlot;
         }
 
         protected LeafCallNode createCacheNode(RootCallTarget cachedTarget) {
@@ -717,7 +709,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             if (explicitArgs) {
                 return PrepareArguments.createExplicit(root);
             } else {
-                CallArgumentsNode args = originalCall.createArguments(dispatchTempIdentifiers, root.getBuiltin() == null, true);
+                CallArgumentsNode args = originalCall.createArguments(tempFrameSlot, root.getBuiltin() == null, true);
                 return PrepareArguments.create(root, args, noOpt);
             }
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
index 41082f5156c4439809ac6c083d56da246f3f28c3..2ddb5474316dbf7260cda12b317c9002b32fb671 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
@@ -23,7 +23,6 @@ import com.oracle.truffle.api.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.ControlFlowException;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
@@ -33,6 +32,7 @@ import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
+import com.oracle.truffle.r.runtime.RArguments.S3Args;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -74,18 +74,22 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
             this.targetFunctionName = targetFunctionName;
             this.groupMatch = groupMatch;
         }
+
+        public S3Args createS3Args(Frame frame) {
+            return new S3Args(generic, clazz, targetFunctionName, frame.materialize(), null, null);
+        }
     }
 
     public static S3FunctionLookupNode create(boolean throwsError, boolean nextMethod) {
-        return new UseMethodFunctionLookupUninitializedNode(throwsError, nextMethod);
+        return new UseMethodFunctionLookupUninitializedNode(throwsError, nextMethod, 0);
     }
 
     public static S3FunctionLookupNode createWithError() {
-        return new UseMethodFunctionLookupUninitializedNode(true, false);
+        return new UseMethodFunctionLookupUninitializedNode(true, false, 0);
     }
 
     public static S3FunctionLookupNode createWithException() {
-        return new UseMethodFunctionLookupUninitializedNode(false, false);
+        return new UseMethodFunctionLookupUninitializedNode(false, false, 0);
     }
 
     @FunctionalInterface
@@ -235,19 +239,21 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
 
     @NodeInfo(cost = NodeCost.UNINITIALIZED)
     private static final class UseMethodFunctionLookupUninitializedNode extends S3FunctionLookupNode {
-        private int depth;
+        private final int depth;
 
-        UseMethodFunctionLookupUninitializedNode(boolean throwsError, boolean nextMethod) {
+        UseMethodFunctionLookupUninitializedNode(boolean throwsError, boolean nextMethod, int depth) {
             super(throwsError, nextMethod);
+            this.depth = depth;
         }
 
         @Override
         public Result execute(VirtualFrame frame, String genericName, RStringVector type, String group, MaterializedFrame callerFrame, MaterializedFrame genericDefFrame) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            if (++depth > MAX_CACHE_DEPTH) {
+            if (depth > MAX_CACHE_DEPTH) {
                 return replace(new UseMethodFunctionLookupGenericNode(throwsError, nextMethod)).execute(frame, genericName, type, group, callerFrame, genericDefFrame);
             } else {
-                UseMethodFunctionLookupCachedNode cachedNode = replace(specialize(frame, genericName, type, group, callerFrame, genericDefFrame, this));
+                UseMethodFunctionLookupCachedNode cachedNode = replace(
+                                specialize(frame, genericName, type, group, callerFrame, genericDefFrame, new UseMethodFunctionLookupUninitializedNode(throwsError, nextMethod, depth + 1)));
                 return cachedNode.execute(frame, genericName, type, group, callerFrame, genericDefFrame);
             }
         }
@@ -329,7 +335,7 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
                     }
                     throw RError.error(this, RError.Message.UNKNOWN_FUNCTION_USE_METHOD, genericName, type);
                 } else {
-                    throw S3FunctionLookupNode.NoGenericMethodException.instance;
+                    return null;
                 }
             } while (true);
             CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -431,19 +437,10 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
                     }
                     throw RError.error(this, RError.Message.UNKNOWN_FUNCTION_USE_METHOD, genericName, RRuntime.toString(type));
                 } else {
-                    throw S3FunctionLookupNode.NoGenericMethodException.instance;
+                    return null;
                 }
             }
             return result;
         }
     }
-
-    @SuppressWarnings("serial")
-    public static final class NoGenericMethodException extends ControlFlowException {
-        private static final NoGenericMethodException instance = new NoGenericMethodException();
-
-        private NoGenericMethodException() {
-            // singleton
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java
index cab3f3c4da90b28fb840338a03006ebcd7bb9b31..03e13b0d068b6a277a8511029d130b4bab6ba20b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/TemporarySlotNode.java
@@ -37,33 +37,35 @@ public final class TemporarySlotNode extends Node {
 
     @CompilationFinal private FrameSlot tempSlot;
     private int tempIdentifier;
-    private Object identifier;
 
-    public void initialize(VirtualFrame frame, Object value, Runnable invalidate) {
+    public FrameSlot initialize(VirtualFrame frame, Object value) {
         if (tempSlot == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier = defaultTempIdentifiers[0], FrameSlotKind.Object);
-            invalidate.run();
+            tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(defaultTempIdentifiers[0], FrameSlotKind.Object);
         }
+        FrameSlot slot = tempSlot;
         try {
-            if (frame.getObject(tempSlot) != null) {
+            if (frame.getObject(slot) != null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 // keep the complete loop in the slow path
                 do {
                     tempIdentifier++;
-                    identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object();
-                    tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier, FrameSlotKind.Object);
-                    invalidate.run();
-                } while (frame.getObject(tempSlot) != null);
+                    Object identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object();
+                    tempSlot = slot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier, FrameSlotKind.Object);
+                    if (frame.getObject(slot) == null) {
+                        break;
+                    }
+                } while (true);
             }
         } catch (FrameSlotTypeException e) {
             CompilerDirectives.transferToInterpreter();
             throw RInternalError.shouldNotReachHere();
         }
-        frame.setObject(tempSlot, value);
+        frame.setObject(slot, value);
+        return slot;
     }
 
-    public void cleanup(VirtualFrame frame, Object object) {
+    public static void cleanup(VirtualFrame frame, Object object, FrameSlot tempSlot) {
         try {
             assert frame.getObject(tempSlot) == object;
         } catch (FrameSlotTypeException e) {
@@ -71,8 +73,4 @@ public final class TemporarySlotNode extends Node {
         }
         frame.setObject(tempSlot, null);
     }
-
-    public Object getIdentifier() {
-        return identifier;
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodInternalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodInternalNode.java
deleted file mode 100644
index 739931976e6def1f5933a27c1c92806339e413c4..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UseMethodInternalNode.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-package com.oracle.truffle.r.nodes.function;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result;
-import com.oracle.truffle.r.runtime.ArgumentsSignature;
-import com.oracle.truffle.r.runtime.FastROptions;
-import com.oracle.truffle.r.runtime.RArguments.S3Args;
-import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.nodes.RNode;
-
-public final class UseMethodInternalNode extends RNode {
-
-    @Child private ClassHierarchyNode classHierarchyNode = ClassHierarchyNodeGen.create(true, true);
-    @Child private S3FunctionLookupNode lookup = S3FunctionLookupNode.create(false, false);
-    @Child private CallMatcherNode callMatcher = CallMatcherNode.create(false);
-    @Child private PreProcessArgumentsNode argPreProcess;
-
-    private final String generic;
-    private final ArgumentsSignature signature;
-    private final boolean wrap;
-
-    public UseMethodInternalNode(String generic, ArgumentsSignature signature, boolean wrap) {
-        this.generic = generic;
-        this.signature = signature;
-        this.wrap = wrap && FastROptions.InvisibleArgs.getBooleanValue();
-    }
-
-    public Object execute(VirtualFrame frame, RStringVector type, Object[] arguments) {
-        Result lookupResult = lookup.execute(frame, generic, type, null, frame.materialize(), null);
-        if (wrap) {
-            assert arguments != null;
-            if (argPreProcess == null || argPreProcess.getLength() != arguments.length) {
-                CompilerDirectives.transferToInterpreterAndInvalidate();
-                argPreProcess = insert(PreProcessArgumentsNode.create(arguments.length));
-            }
-            argPreProcess.execute(frame, arguments);
-        }
-        S3Args s3Args = new S3Args(generic, lookupResult.clazz, lookupResult.targetFunctionName, frame.materialize(), null, null);
-        return callMatcher.execute(frame, signature, arguments, lookupResult.function, lookupResult.targetFunctionName, s3Args);
-    }
-
-    @Override
-    public Object execute(VirtualFrame frame) {
-        throw RInternalError.shouldNotReachHere();
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java
index 7ed844a144758904c56d2f9e9463f19e2c1d3673..8a6471d4845ffb956178fdb29cb6fac32f94240a 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentNode.java
@@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.function;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.UnexpectedResultException;
-import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -44,8 +43,6 @@ public final class WrapArgumentNode extends WrapArgumentBaseNode {
 
     @Child private ArgumentStatePush argPushStateNode;
 
-    private final BranchProfile refCounted = BranchProfile.create();
-
     private WrapArgumentNode(RNode operand, boolean modeChange, int index) {
         super(operand, modeChange);
         this.modeChange = modeChange;
@@ -79,9 +76,6 @@ public final class WrapArgumentNode extends WrapArgumentBaseNode {
             if (rShareable != null) {
                 shareable.enter();
                 argPushStateNode.executeObject(frame, rShareable);
-            } else if (argPushStateNode.refCounted()) {
-                refCounted.enter();
-                argPushStateNode.executeObject(frame, RNull.instance);
             }
         }
         return result;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
index 60218f9968d1610f1a04a6f303e88eb16bbd1e53..5b48ec10193c4ede8faf5340e4ed14b5eee1032d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/PrepareArguments.java
@@ -23,15 +23,23 @@
 package com.oracle.truffle.r.nodes.function.call;
 
 import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Fallback;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.RRootNode;
 import com.oracle.truffle.r.nodes.function.ArgumentMatcher;
 import com.oracle.truffle.r.nodes.function.ArgumentMatcher.MatchPermutation;
 import com.oracle.truffle.r.nodes.function.CallArgumentsNode;
 import com.oracle.truffle.r.nodes.function.FormalArguments;
 import com.oracle.truffle.r.nodes.function.RCallNode;
+import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsDefaultNodeGen;
+import com.oracle.truffle.r.nodes.function.call.PrepareArgumentsFactory.PrepareArgumentsExplicitNodeGen;
 import com.oracle.truffle.r.runtime.Arguments;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments;
@@ -44,171 +52,111 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
  * rules. It implements two different paths: one for arguments provided as an
  * {@link CallArgumentsNode}, i.e., unevaluated arguments, and another path for evaluated arguments.
  */
+@TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 public abstract class PrepareArguments extends Node {
 
-    private static final int CACHE_SIZE = 4;
+    protected static final int CACHE_SIZE = 8;
 
-    /**
-     * Returns the argument values and corresponding signature. The signature represents the
-     * original call signature reordered in the same way as the arguments. For s3DefaultArguments
-     * motivation see {@link RCallNode#callGroupGeneric}.
-     */
-    public abstract RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call);
+    abstract static class PrepareArgumentsDefault extends PrepareArguments {
 
-    public static PrepareArguments create(RRootNode target, CallArgumentsNode args, boolean noOpt) {
-        return new UninitializedPrepareArguments(target, args, noOpt);
-    }
+        protected final RRootNode target;
+        protected final CallArgumentsNode sourceArguments; // not used as a node
+        protected final boolean noOpt;
 
-    public static PrepareArguments createExplicit(RRootNode target) {
-        return new UninitializedExplicitPrepareArguments(target);
-    }
+        static final class ArgumentsAndSignature extends Node {
+            @Children private final RNode[] matchedArguments;
+            private final ArgumentsSignature matchedSuppliedSignature;
 
-    @ExplodeLoop
-    private static RArgsValuesAndNames executeArgs(RNode[] arguments, ArgumentsSignature suppliedSignature, VirtualFrame frame) {
-        Object[] result = new Object[arguments.length];
-        for (int i = 0; i < arguments.length; i++) {
-            result[i] = arguments[i].execute(frame);
+            protected ArgumentsAndSignature(RNode[] matchedArguments, ArgumentsSignature matchedSuppliedSignature) {
+                this.matchedArguments = matchedArguments;
+                this.matchedSuppliedSignature = matchedSuppliedSignature;
+            }
         }
-        return new RArgsValuesAndNames(result, suppliedSignature);
-    }
-
-    private static RArgsValuesAndNames executeArgs(Arguments<RNode> matched, VirtualFrame frame) {
-        return executeArgs(matched.getArguments(), matched.getSignature(), frame);
-    }
-
-    private static final class UninitializedPrepareArguments extends PrepareArguments {
 
-        private final RRootNode target;
-        private final CallArgumentsNode sourceArguments; // not used as a node
-        private final boolean noOpt;
-        private int depth = CACHE_SIZE;
+        protected static ArgumentsSignature getSignatureOrNull(RArgsValuesAndNames args) {
+            return args == null ? null : args.getSignature();
+        }
 
-        UninitializedPrepareArguments(RRootNode target, CallArgumentsNode sourceArguments, boolean noOpt) {
+        protected PrepareArgumentsDefault(RRootNode target, CallArgumentsNode sourceArguments, boolean noOpt) {
             this.target = target;
             this.sourceArguments = sourceArguments;
             this.noOpt = noOpt;
         }
 
-        @Override
-        public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            PrepareArguments next;
-            if (depth-- > 0) {
-                next = new CachedPrepareArguments(this, target, call, sourceArguments, varArgs == null ? null : varArgs.getSignature(), s3DefaultArguments, noOpt);
-            } else {
-                next = new GenericPrepareArguments(target, sourceArguments);
-            }
-            return replace(next).execute(frame, varArgs, s3DefaultArguments, call);
-        }
-    }
-
-    private static final class CachedPrepareArguments extends PrepareArguments {
-
-        @Child private PrepareArguments next;
-        @Children private final RNode[] matchedArguments;
-        private final ArgumentsSignature matchedSuppliedSignature;
-        private final ArgumentsSignature cachedVarArgSignature;
-        private final Object cachedS3DefaultArguments;
-
-        CachedPrepareArguments(PrepareArguments next, RRootNode target, RCallNode call, CallArgumentsNode args, ArgumentsSignature varArgSignature, S3DefaultArguments s3DefaultArguments,
-                        boolean noOpt) {
-            this.next = next;
-            cachedVarArgSignature = varArgSignature;
-            Arguments<RNode> matched = ArgumentMatcher.matchArguments(target, args, varArgSignature, s3DefaultArguments, call, noOpt);
-            this.matchedArguments = matched.getArguments();
-            this.matchedSuppliedSignature = matched.getSignature();
-            this.cachedS3DefaultArguments = s3DefaultArguments;
+        protected ArgumentsAndSignature createArguments(RCallNode call, ArgumentsSignature varArgSignature, S3DefaultArguments s3DefaultArguments) {
+            Arguments<RNode> matched = ArgumentMatcher.matchArguments(target, sourceArguments, varArgSignature, s3DefaultArguments, call, noOpt);
+            return new ArgumentsAndSignature(matched.getArguments(), matched.getSignature());
         }
 
-        @Override
         @ExplodeLoop
-        public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
-            assert (cachedVarArgSignature != null) == (varArgs != null);
-            if ((cachedVarArgSignature == null || cachedVarArgSignature == varArgs.getSignature()) && cachedS3DefaultArguments == s3DefaultArguments) {
-                return executeArgs(matchedArguments, matchedSuppliedSignature, frame);
+        private static RArgsValuesAndNames executeArgs(RNode[] arguments, ArgumentsSignature suppliedSignature, VirtualFrame frame) {
+            Object[] result = new Object[arguments.length];
+            for (int i = 0; i < arguments.length; i++) {
+                result[i] = arguments[i].execute(frame);
             }
-            return next.execute(frame, varArgs, s3DefaultArguments, call);
+            return new RArgsValuesAndNames(result, suppliedSignature);
         }
-    }
-
-    private static final class GenericPrepareArguments extends PrepareArguments {
 
-        private final RRootNode target;
-        private final CallArgumentsNode args; // not used as a node
-
-        GenericPrepareArguments(RRootNode target, CallArgumentsNode args) {
-            this.target = target;
-            this.args = args;
+        @Specialization(limit = "CACHE_SIZE", guards = {"cachedVarArgSignature == null || cachedVarArgSignature == varArgs.getSignature()", "cachedS3DefaultArguments == s3DefaultArguments"})
+        public RArgsValuesAndNames prepare(VirtualFrame frame, RArgsValuesAndNames varArgs, @SuppressWarnings("unused") S3DefaultArguments s3DefaultArguments,
+                        @SuppressWarnings("unused") RCallNode call,
+                        @Cached("getSignatureOrNull(varArgs)") ArgumentsSignature cachedVarArgSignature,
+                        @Cached("createArguments(call, cachedVarArgSignature, s3DefaultArguments)") ArgumentsAndSignature arguments,
+                        @SuppressWarnings("unused") @Cached("s3DefaultArguments") S3DefaultArguments cachedS3DefaultArguments) {
+            assert (cachedVarArgSignature != null) == (varArgs != null);
+            return executeArgs(arguments.matchedArguments, arguments.matchedSuppliedSignature, frame);
         }
 
-        @Override
-        public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
+        @Fallback
+        public RArgsValuesAndNames prepareGeneric(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call) {
             CompilerDirectives.transferToInterpreter();
             ArgumentsSignature varArgSignature = varArgs == null ? null : varArgs.getSignature();
-            Arguments<RNode> matchedArgs = ArgumentMatcher.matchArguments(target, args, varArgSignature, s3DefaultArguments, RError.ROOTNODE, true);
-            return executeArgs(matchedArgs, frame);
+            Arguments<RNode> matchedArgs = ArgumentMatcher.matchArguments(target, sourceArguments, varArgSignature, s3DefaultArguments, RError.ROOTNODE, true);
+            return executeArgs(matchedArgs.getArguments(), matchedArgs.getSignature(), frame);
         }
     }
 
-    private static final class UninitializedExplicitPrepareArguments extends PrepareArguments {
+    abstract static class PrepareArgumentsExplicit extends PrepareArguments {
 
-        private final RRootNode target;
-        private int depth = CACHE_SIZE;
+        protected final RRootNode target;
+        private final FormalArguments formals;
 
-        UninitializedExplicitPrepareArguments(RRootNode target) {
+        protected PrepareArgumentsExplicit(RRootNode target) {
             this.target = target;
+            this.formals = target.getFormalArguments();
         }
 
-        @Override
-        public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            PrepareArguments next;
-            if (depth-- > 0) {
-                next = new CachedExplicitPrepareArguments(this, target, call, explicitArgs == null ? null : explicitArgs.getSignature());
-            } else {
-                next = new GenericExplicitPrepareArguments(target);
-            }
-            return replace(next).execute(frame, explicitArgs, s3DefaultArguments, call);
+        protected MatchPermutation createArguments(RCallNode call, ArgumentsSignature explicitArgSignature) {
+            return ArgumentMatcher.matchArguments(explicitArgSignature, formals.getSignature(), call, target.getBuiltin());
         }
-    }
-
-    private static final class CachedExplicitPrepareArguments extends PrepareArguments {
-
-        @Child private PrepareArguments next;
-
-        private final MatchPermutation permutation;
-        private final ArgumentsSignature cachedExplicitArgSignature;
-        private final FormalArguments formals;
 
-        CachedExplicitPrepareArguments(PrepareArguments next, RRootNode target, RCallNode call, ArgumentsSignature explicitArgSignature) {
-            this.next = next;
-            formals = target.getFormalArguments();
-            permutation = ArgumentMatcher.matchArguments(explicitArgSignature, formals.getSignature(), call, target.getBuiltin());
-            cachedExplicitArgSignature = explicitArgSignature;
+        @Specialization(limit = "CACHE_SIZE", guards = {"cachedExplicitArgSignature == explicitArgs.getSignature()"})
+        public RArgsValuesAndNames prepare(RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call,
+                        @SuppressWarnings("unused") @Cached("explicitArgs.getSignature()") ArgumentsSignature cachedExplicitArgSignature,
+                        @Cached("createArguments(call, cachedExplicitArgSignature)") MatchPermutation permutation) {
+            return ArgumentMatcher.matchArgumentsEvaluated(permutation, explicitArgs.getArguments(), s3DefaultArguments, formals);
         }
 
-        @Override
-        public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
-            if (cachedExplicitArgSignature == explicitArgs.getSignature()) {
-                return ArgumentMatcher.matchArgumentsEvaluated(permutation, explicitArgs.getArguments(), s3DefaultArguments, formals);
-            }
-            return next.execute(frame, explicitArgs, s3DefaultArguments, call);
+        @Fallback
+        @TruffleBoundary
+        public RArgsValuesAndNames prepareGeneric(RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, @SuppressWarnings("unused") RCallNode call) {
+            // Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/
+            return ArgumentMatcher.matchArgumentsEvaluated(target, explicitArgs, s3DefaultArguments, RError.ROOTNODE);
         }
     }
 
-    private static final class GenericExplicitPrepareArguments extends PrepareArguments {
-
-        private final RRootNode target;
+    /**
+     * Returns the argument values and corresponding signature. The signature represents the
+     * original call signature reordered in the same way as the arguments. For s3DefaultArguments
+     * motivation see {@link RCallNode#callGroupGeneric}.
+     */
+    public abstract RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames varArgs, S3DefaultArguments s3DefaultArguments, RCallNode call);
 
-        GenericExplicitPrepareArguments(RRootNode target) {
-            this.target = target;
-        }
+    public static PrepareArguments create(RRootNode target, CallArgumentsNode args, boolean noOpt) {
+        return PrepareArgumentsDefaultNodeGen.create(target, args, noOpt);
+    }
 
-        @Override
-        public RArgsValuesAndNames execute(VirtualFrame frame, RArgsValuesAndNames explicitArgs, S3DefaultArguments s3DefaultArguments, RCallNode call) {
-            CompilerDirectives.transferToInterpreter();
-            // Function and arguments may change every call: Flatt'n'Match on SlowPath! :-/
-            return ArgumentMatcher.matchArgumentsEvaluated(target, explicitArgs, s3DefaultArguments, RError.ROOTNODE);
-        }
+    public static PrepareArguments createExplicit(RRootNode target) {
+        return PrepareArgumentsExplicitNodeGen.create(target);
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java
index 235264d8223d504e607cfffac0f69e535ecf3017..be53842774b8ccb73b1a0cdf99dc7a8322c0a420 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestTestBase.java
@@ -55,7 +55,7 @@ public class TestTestBase extends TestBase {
                         getCode("cat('Warning message: In .Internal(foo(42)): IgnoreWarningContext diff message')", "cat('Warning message in foo(42): IgnoreWarningContext should fail')"));
     }
 
-    private String getCode(String fastr, String gnur) {
+    private static String getCode(String fastr, String gnur) {
         return "if (exists('.fastr.identity')) { " + fastr + " } else { " + gnur + " }";
     }
 }