diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IntersectFastPath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IntersectFastPath.java
index e0f1161c1d5415edda8156fef193ab9269f7bafa..611cf68d898d0ed50f0630d15a1059eee1cf0174 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IntersectFastPath.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/IntersectFastPath.java
@@ -36,35 +36,43 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 
 public abstract class IntersectFastPath extends RFastPathNode {
 
+    protected static final int TYPE_LIMIT = 2;
+
     private static final int[] EMPTY_INT_ARRAY = new int[0];
 
-    @Specialization(guards = {"x.getLength() > 0", "y.getLength() > 0"})
-    protected RAbstractIntVector intersect(RAbstractIntVector x, RAbstractIntVector y, //
-                    @Cached("createBinaryProfile()") ConditionProfile isXSortedProfile, //
-                    @Cached("createBinaryProfile()") ConditionProfile isYSortedProfile, //
+    @Specialization(limit = "TYPE_LIMIT", guards = {"x.getLength() > 0", "y.getLength() > 0", "x.getClass() == xClass", "y.getClass() == yClass"})
+    protected RAbstractIntVector intersect(RAbstractIntVector x, RAbstractIntVector y,
+                    @Cached("x.getClass()") Class<? extends RAbstractIntVector> xClass,
+                    @Cached("y.getClass()") Class<? extends RAbstractIntVector> yClass,
+                    @Cached("createBinaryProfile()") ConditionProfile isXSortedProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile isYSortedProfile,
                     @Cached("createBinaryProfile()") ConditionProfile resultLengthMatchProfile) {
-        int xLength = x.getLength();
-        int yLength = y.getLength();
+        // apply the type profiles:
+        RAbstractIntVector profiledX = xClass.cast(x);
+        RAbstractIntVector profiledY = yClass.cast(y);
+
+        int xLength = profiledX.getLength();
+        int yLength = profiledY.getLength();
         RNode.reportWork(this, xLength + yLength);
 
         int count = 0;
         int[] result = EMPTY_INT_ARRAY;
         int maxResultLength = Math.min(xLength, yLength);
-        if (isXSortedProfile.profile(isSorted(x))) {
+        if (isXSortedProfile.profile(isSorted(profiledX))) {
             RAbstractIntVector tempY;
-            if (!isYSortedProfile.profile(isSorted(y))) {
+            if (isYSortedProfile.profile(isSorted(profiledY))) {
+                tempY = profiledY;
+            } else {
                 int[] temp = new int[yLength];
                 for (int i = 0; i < yLength; i++) {
-                    temp[i] = y.getDataAt(i);
+                    temp[i] = profiledY.getDataAt(i);
                 }
                 sort(temp);
-                tempY = RDataFactory.createIntVector(temp, y.isComplete());
-            } else {
-                tempY = y;
+                tempY = RDataFactory.createIntVector(temp, profiledY.isComplete());
             }
             int xPos = 0;
             int yPos = 0;
-            int xValue = x.getDataAt(xPos);
+            int xValue = profiledX.getDataAt(xPos);
             int yValue = tempY.getDataAt(yPos);
             while (true) {
                 if (xValue == yValue) {
@@ -77,7 +85,7 @@ public abstract class IntersectFastPath extends RFastPathNode {
                         if (xPos >= xLength - 1) {
                             break;
                         }
-                        int nextValue = x.getDataAt(xPos + 1);
+                        int nextValue = profiledX.getDataAt(xPos + 1);
                         if (xValue != nextValue) {
                             break;
                         }
@@ -87,13 +95,13 @@ public abstract class IntersectFastPath extends RFastPathNode {
                     if (++xPos >= xLength || ++yPos >= yLength) {
                         break;
                     }
-                    xValue = x.getDataAt(xPos);
+                    xValue = profiledX.getDataAt(xPos);
                     yValue = tempY.getDataAt(yPos);
                 } else if (xValue < yValue) {
                     if (++xPos >= xLength) {
                         break;
                     }
-                    xValue = x.getDataAt(xPos);
+                    xValue = profiledX.getDataAt(xPos);
                 } else {
                     if (++yPos >= yLength) {
                         break;
@@ -105,12 +113,12 @@ public abstract class IntersectFastPath extends RFastPathNode {
             int[] temp = new int[yLength];
             boolean[] used = new boolean[yLength];
             for (int i = 0; i < yLength; i++) {
-                temp[i] = y.getDataAt(i);
+                temp[i] = profiledY.getDataAt(i);
             }
             sort(temp);
 
             for (int i = 0; i < xLength; i++) {
-                int value = x.getDataAt(i);
+                int value = profiledX.getDataAt(i);
                 int pos = Arrays.binarySearch(temp, value);
                 if (pos >= 0 && !used[pos]) {
                     used[pos] = true;
@@ -121,7 +129,7 @@ public abstract class IntersectFastPath extends RFastPathNode {
                 }
             }
         }
-        return RDataFactory.createIntVector(resultLengthMatchProfile.profile(count == result.length) ? result : Arrays.copyOf(result, count), x.isComplete() | y.isComplete());
+        return RDataFactory.createIntVector(resultLengthMatchProfile.profile(count == result.length) ? result : Arrays.copyOf(result, count), profiledX.isComplete() | profiledY.isComplete());
     }
 
     private static boolean isSorted(RAbstractIntVector vector) {
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 a45022312ca4653b6c161b8c0734e45354ef3108..f600dd260b59b01622b64f07457435d412e2974c 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
@@ -65,49 +65,51 @@ public abstract class ArgumentStatePush extends Node {
     public void transitionState(VirtualFrame frame, RShareable shareable) {
         if (isRefCountUpdateable.profile(!shareable.isSharedPermanent())) {
             shareable.incRefCount();
-        }
-        if (!FastROptions.RefCountIncrementOnly.getBooleanValue()) {
-            if (mask == 0) {
-                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
+            if (!FastROptions.RefCountIncrementOnly.getBooleanValue()) {
+                if (mask == 0) {
+                    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)));
                 }
-                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;
+                if (mask != -1) {
+                    writeArgNode.execute(frame, shareable);
                 }
-                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);
             }
         }
     }
@@ -135,8 +137,7 @@ public abstract class ArgumentStatePush extends Node {
         // this is expected to be used in rare cases where no RNode is easily available
         if (o instanceof RShareable) {
             RShareable shareable = (RShareable) o;
-            // it's never decremented so no point in incrementing past shared state
-            if (!shareable.isShared()) {
+            if (!shareable.isSharedPermanent()) {
                 shareable.incRefCount();
             }
         }
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 b26a5aca8397d77862132affd87663c5c274bbe6..52c81b0097da24334ee814cd0ebeadc4c0875a90 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
@@ -34,7 +34,6 @@ import com.oracle.truffle.api.dsl.Cached;
 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.frame.FrameSlot;
 import com.oracle.truffle.api.frame.FrameSlotTypeException;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
@@ -45,7 +44,6 @@ import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeCost;
 import com.oracle.truffle.api.nodes.NodeInfo;
-import com.oracle.truffle.api.nodes.NodeUtil;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.nodes.UnexpectedResultException;
 import com.oracle.truffle.api.profiles.BranchProfile;
@@ -312,7 +310,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
     }
 
     protected RNode createDispatchArgument(int index) {
-        return new ForcePromiseNode(NodeUtil.cloneNode(arguments[index].asRNode()));
+        return new ForcePromiseNode(RASTUtils.cloneNode(arguments[index].asRNode()));
     }
 
     /**
@@ -339,7 +337,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);
-        FrameSlot slot = dispatchTempSlot.initialize(frame, dispatchObject, () -> internalDispatchCall = null);
+        dispatchTempSlot.initialize(frame, dispatchObject, () -> internalDispatchCall = null);
         try {
             RStringVector type = classHierarchyNode.execute(dispatchObject);
             S3Args s3Args;
@@ -362,7 +360,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             }
             return internalDispatchCall.execute(frame, resultFunction, lookupVarArgs(frame), s3Args, null);
         } finally {
-            dispatchTempSlot.cleanup(frame, slot);
+            dispatchTempSlot.cleanup(frame, dispatchObject);
         }
     }
 
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 56c0751202f6e38fef94f115bb4dcf895ce01efc..cab3f3c4da90b28fb840338a03006ebcd7bb9b31 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
@@ -23,50 +23,53 @@
 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.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;
-import com.oracle.truffle.r.nodes.access.FrameSlotNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 
 public final class TemporarySlotNode extends Node {
 
     private static final Object[] defaultTempIdentifiers = new Object[]{new Object(), new Object(), new Object(), new Object(), new Object(), new Object(), new Object(), new Object()};
 
-    @Child private FrameSlotNode tempSlot;
+    @CompilationFinal private FrameSlot tempSlot;
     private int tempIdentifier;
     private Object identifier;
 
-    public FrameSlot initialize(VirtualFrame frame, Object value, Runnable invalidate) {
+    public void initialize(VirtualFrame frame, Object value, Runnable invalidate) {
         if (tempSlot == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            tempSlot = insert(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), identifier = defaultTempIdentifiers[0], true));
+            tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier = defaultTempIdentifiers[0], FrameSlotKind.Object);
             invalidate.run();
         }
-        FrameSlot slot = tempSlot.executeFrameSlot(frame);
         try {
-            if (frame.isObject(slot) && frame.getObject(slot) != null) {
+            if (frame.getObject(tempSlot) != null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
                 // keep the complete loop in the slow path
                 do {
                     tempIdentifier++;
                     identifier = tempIdentifier < defaultTempIdentifiers.length ? defaultTempIdentifiers[tempIdentifier] : new Object();
-                    tempSlot.replace(FrameSlotNode.createInitialized(frame.getFrameDescriptor(), identifier, true));
+                    tempSlot = frame.getFrameDescriptor().findOrAddFrameSlot(identifier, FrameSlotKind.Object);
                     invalidate.run();
-                    slot = tempSlot.executeFrameSlot(frame);
-                } while (frame.isObject(slot) && frame.getObject(slot) != null);
+                } while (frame.getObject(tempSlot) != null);
             }
         } catch (FrameSlotTypeException e) {
+            CompilerDirectives.transferToInterpreter();
             throw RInternalError.shouldNotReachHere();
         }
-        frame.setObject(slot, value);
-        return slot;
+        frame.setObject(tempSlot, value);
     }
 
-    @SuppressWarnings("static-method")
-    public void cleanup(VirtualFrame frame, FrameSlot slot) {
-        frame.setObject(slot, null);
+    public void cleanup(VirtualFrame frame, Object object) {
+        try {
+            assert frame.getObject(tempSlot) == object;
+        } catch (FrameSlotTypeException e) {
+            throw RInternalError.shouldNotReachHere();
+        }
+        frame.setObject(tempSlot, null);
     }
 
     public Object getIdentifier() {