diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
index aa454c0002d8a29000c90055b468fb1ee87c8f77..eac4155fc6ef9de92adcbeb290f9d4c86f671876 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java
@@ -37,6 +37,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.NodeChild;
@@ -44,6 +45,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.CombineNodeGen.CombineInputCastNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastComplexNodeGen;
@@ -55,7 +57,6 @@ import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.nodes.unary.CastRawNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
-import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen;
 import com.oracle.truffle.r.nodes.unary.PrecedenceNode;
 import com.oracle.truffle.r.nodes.unary.PrecedenceNodeGen;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
@@ -86,10 +87,19 @@ public abstract class Combine extends RBuiltinNode {
 
     protected static final int COMBINE_CACHED_LIMIT = PrecedenceNode.NUMBER_OF_PRECEDENCES;
 
+    private static final int MAX_PROFILES = 4;
+
     @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create();
     @Child private CombineInputCast inputCast = CombineInputCastNodeGen.create(null);
     @Child private CastToVectorNode castVector;
+
     private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+    private final BranchProfile naBranch = BranchProfile.create();
+    private final NACheck naCheck = NACheck.create();
+    private final ConditionProfile fastNamesMerge = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile isAbstractVectorProfile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile hasNewNamesProfile = ConditionProfile.createBinaryProfile();
+    @CompilationFinal private final ValueProfile[] argProfiles = new ValueProfile[MAX_PROFILES];
 
     public abstract Object executeCombine(Object value);
 
@@ -107,9 +117,7 @@ public abstract class Combine extends RBuiltinNode {
                     @Cached("args.getSignature()") ArgumentsSignature cachedSignature, //
                     @Cached("precedence( args, cachedSignature.getLength())") int cachedPrecedence, //
                     @Cached("createCast(cachedPrecedence)") CastNode cast, //
-                    @Cached("create()") BranchProfile naBranch, //
                     @Cached("create()") BranchProfile naNameBranch, //
-                    @Cached("create()") NACheck naCheck, //
                     @Cached("create()") NACheck naNameCheck, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile) {
         CompilerAsserts.partialEvaluationConstant(cachedSignature);
@@ -121,13 +129,15 @@ public abstract class Combine extends RBuiltinNode {
 
         // perform all the casts
         Object[] elements = new Object[cachedSignature.getLength()];
-        int size = prepareElements(args.getArguments(), cachedSignature, cast, cachedPrecedence, elements);
+        int size = prepareElements(args.getArguments(), cast, cachedPrecedence, elements);
 
         // prepare the names (if there are any)
-        RStringVector namesVector = hasNamesProfile.profile(hasNames(elements)) ? foldNames(naNameBranch, naNameCheck, elements, size) : null;
+        boolean signatureHasNames = signatureHasNames(cachedSignature);
+        CompilerAsserts.partialEvaluationConstant(signatureHasNames);
+        RStringVector namesVector = hasNamesProfile.profile(signatureHasNames || hasNames(elements)) ? foldNames(naNameBranch, naNameCheck, elements, size, cachedSignature) : null;
 
         // get the actual contents of the result
-        RVector result = foldContents(cachedPrecedence, naBranch, naCheck, elements, size, namesVector);
+        RVector result = foldContents(cachedPrecedence, elements, size, namesVector);
 
         RNode.reportWork(this, size);
 
@@ -139,13 +149,17 @@ public abstract class Combine extends RBuiltinNode {
     }
 
     @ExplodeLoop
-    private int prepareElements(Object[] args, ArgumentsSignature signature, CastNode cast, int precedence, Object[] elements) {
-        boolean signatureHasNames = signatureHasNames(signature);
-        CompilerAsserts.partialEvaluationConstant(signatureHasNames);
-
+    private int prepareElements(Object[] args, CastNode cast, int precedence, Object[] elements) {
         int size = 0;
         for (int i = 0; i < elements.length; i++) {
-            Object element = readAndCast(cast, args, signature, i, precedence, signatureHasNames);
+            Object element = readAndCast(cast, args[i], precedence);
+            if (i < argProfiles.length) {
+                if (argProfiles[i] == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    argProfiles[i] = ValueProfile.createClassProfile();
+                }
+                element = argProfiles[i].profile(element);
+            }
             elements[i] = element;
             size += getElementSize(element);
         }
@@ -165,7 +179,11 @@ public abstract class Combine extends RBuiltinNode {
 
     @ExplodeLoop
     private boolean hasNames(Object[] elements) {
-        for (Object element : elements) {
+        for (int i = 0; i < elements.length; i++) {
+            Object element = elements[i];
+            if (i < argProfiles.length) {
+                element = argProfiles[i].profile(element);
+            }
             if (element instanceof RAbstractVector) {
                 RAbstractVector vector = (RAbstractVector) element;
                 if (vector.getNames(attrProfiles) != null) {
@@ -177,22 +195,36 @@ public abstract class Combine extends RBuiltinNode {
     }
 
     @ExplodeLoop
-    private RStringVector foldNames(BranchProfile naNameBranch, NACheck naNameCheck, Object[] elements, int size) {
+    private RStringVector foldNames(BranchProfile naNameBranch, NACheck naNameCheck, Object[] elements, int size, ArgumentsSignature signature) {
         RStringVector result = RDataFactory.createStringVector(new String[size], true);
         result.incRefCount();
         int pos = 0;
-        for (Object element : elements) {
-            pos += processNamesElement(naNameBranch, naNameCheck, result, pos, element);
+        for (int i = 0; i < elements.length; i++) {
+            Object element = elements[i];
+            if (i < argProfiles.length) {
+                element = argProfiles[i].profile(element);
+            }
+            pos += processNamesElement(naNameBranch, naNameCheck, result, pos, element, i, signature);
         }
         return result;
     }
 
-    private int processNamesElement(BranchProfile naNameBranch, NACheck naNameCheck, RStringVector result, int pos, Object element) {
+    private int processNamesElement(BranchProfile naNameBranch, NACheck naNameCheck, RStringVector result, int pos, Object element, int index, ArgumentsSignature signature) {
+        String signatureName = signature.getName(index);
         if (element instanceof RAbstractVector) {
             RAbstractVector v = (RAbstractVector) element;
+            int length = v.getLength();
+
             RStringVector newNames = v.getNames(attrProfiles);
-            if (newNames != null) {
-                for (int i1 = 0; i1 < newNames.getLength(); i1++) {
+            if (signatureName != null && length > 0) {
+                if (fastNamesMerge.profile(length == 1 && newNames == null)) {
+                    newNames = RDataFactory.createStringVector(new String[]{signatureName}, true);
+                } else {
+                    newNames = RDataFactory.createStringVector(mergeNamesSlow(length, signatureName, newNames), true);
+                }
+            }
+            if (hasNewNamesProfile.profile(newNames != null)) {
+                for (int i1 = 0; i1 < length; i1++) {
                     result.transferElementSameType(pos + i1, newNames, i1);
                 }
                 if (!newNames.isComplete()) {
@@ -200,7 +232,7 @@ public abstract class Combine extends RBuiltinNode {
                     result.setComplete(false);
                 }
             } else {
-                for (int i1 = 0; i1 < v.getLength(); i1++) {
+                for (int i1 = 0; i1 < length; i1++) {
                     result.updateDataAt(pos + i1, RRuntime.NAMES_ATTR_EMPTY_VALUE, naNameCheck);
                 }
             }
@@ -209,23 +241,24 @@ public abstract class Combine extends RBuiltinNode {
             // nothing to do - NULL elements are skipped
             return 0;
         } else {
-            result.updateDataAt(pos, RRuntime.NAMES_ATTR_EMPTY_VALUE, naNameCheck);
+            String name = signatureName != null ? signatureName : RRuntime.NAMES_ATTR_EMPTY_VALUE;
+            result.updateDataAt(pos, name, naNameCheck);
             return 1;
         }
     }
 
     @ExplodeLoop
-    private static RVector foldContents(int cachedPrecedence, BranchProfile naBranch, NACheck naCheck, Object[] elements, int size, RStringVector namesVector) {
+    private RVector foldContents(int cachedPrecedence, Object[] elements, int size, RStringVector namesVector) {
         RVector result = createResultVector(cachedPrecedence, size, namesVector);
         int pos = 0;
         for (Object element : elements) {
-            pos += processContentElement(naBranch, naCheck, result, pos, element);
+            pos += processContentElement(result, pos, element);
         }
         return result;
     }
 
-    private static int processContentElement(BranchProfile naBranch, NACheck naCheck, RVector result, int pos, Object element) {
-        if (element instanceof RAbstractVector) {
+    private int processContentElement(RVector result, int pos, Object element) {
+        if (isAbstractVectorProfile.profile(element instanceof RAbstractVector)) {
             RAbstractVector v = (RAbstractVector) element;
             for (int i = 0; i < v.getLength(); i++) {
                 result.transferElementSameType(pos + i, v, i);
@@ -254,12 +287,10 @@ public abstract class Combine extends RBuiltinNode {
     protected Object combine(RArgsValuesAndNames args, //
                     @Cached("precedence(args, args.getLength())") int cachedPrecedence, //
                     @Cached("createCast(cachedPrecedence)") CastNode cast, //
-                    @Cached("create()") BranchProfile naBranch, //
                     @Cached("create()") BranchProfile naNameBranch, //
-                    @Cached("create()") NACheck naCheck, //
                     @Cached("create()") NACheck naNameCheck, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile) {
-        return combineCached(args, args.getSignature(), cachedPrecedence, cast, naBranch, naNameBranch, naCheck, naNameCheck, hasNamesProfile);
+        return combineCached(args, args.getSignature(), cachedPrecedence, cast, naNameBranch, naNameCheck, hasNamesProfile);
     }
 
     @Specialization(guards = "!isArguments(args)")
@@ -267,39 +298,11 @@ public abstract class Combine extends RBuiltinNode {
         return combine.executeCombine(new RArgsValuesAndNames(new Object[]{args}, EMPTY_SIGNATURE));
     }
 
-    private Object readAndCast(CastNode castNode, Object[] values, ArgumentsSignature signature, int index, int precedence, boolean hasNames) {
-        Object value = inputCast.execute(values[index]);
-        if (hasNames) {
-            value = namesMerge(castVector(value), signature.getName(index));
-        }
+    private Object readAndCast(CastNode castNode, Object arg, int precedence) {
+        Object value = inputCast.execute(arg);
         return (precedence == EXPRESSION_PRECEDENCE && value instanceof RLanguage) ? value : castNode.execute(value);
     }
 
-    private RAbstractVector namesMerge(RAbstractVector vector, String name) {
-        RStringVector orgNamesObject = vector.getNames(attrProfiles);
-        if (name == null) {
-            return vector;
-        }
-        if (vector.getLength() == 0) {
-            return vector;
-        }
-        return mergeNamesSlow(vector, name, orgNamesObject);
-    }
-
-    private RAbstractVector castVector(Object value) {
-        if (castVector == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            castVector = insert(CastToVectorNodeGen.create(false));
-        }
-        RVector resultVector = ((RAbstractVector) castVector.execute(value)).materialize();
-        // need to copy if vector is shared in case the same variable is used in combine, e.g. :
-        // x <- 1:2 ; names(x) <- c("A",NA) ; c(x,test=x)
-        if (resultVector.isShared()) {
-            resultVector = resultVector.copy();
-        }
-        return resultVector;
-    }
-
     protected int precedence(RArgsValuesAndNames args) {
         int precedence = NO_PRECEDENCE;
         Object[] array = args.getArguments();
@@ -376,37 +379,30 @@ public abstract class Combine extends RBuiltinNode {
     }
 
     @TruffleBoundary
-    private static RAbstractVector mergeNamesSlow(RAbstractVector vector, String name, RStringVector orgNames) {
-        /*
-         * TODO (chumer) we should reuse some node for this to concat a RStringVector with a String.
-         */
-        RVector v = vector.materialize();
-        RStringVector newNames;
+    private static String[] mergeNamesSlow(int length, String name, RStringVector orgNames) {
+        String[] names = new String[length];
         if (orgNames == null) {
             assert (name != null);
             assert (!name.equals(RRuntime.NAMES_ATTR_EMPTY_VALUE));
-            if (v.getLength() == 1) {
+            if (length == 1) {
                 // single value - just use the name
-                newNames = RDataFactory.createStringVector(new String[]{name}, true);
+                names[0] = name;
             } else {
                 // multiple values - prepend name to the index of a given value
-                String[] names = new String[v.getLength()];
                 for (int i = 0; i < names.length; i++) {
                     names[i] = name + (i + 1);
                 }
-                newNames = RDataFactory.createStringVector(names, true);
+                return names;
             }
         } else {
-            if (vector.getLength() == 1) {
-                // single value
-                // prepend name to the original name
+            if (length == 1) {
+                // single value - prepend name to the original name
                 assert (!name.equals(RRuntime.NAMES_ATTR_EMPTY_VALUE));
                 String orgName = orgNames.getDataAt(0);
-                newNames = RDataFactory.createStringVector(new String[]{orgName.equals(RRuntime.NAMES_ATTR_EMPTY_VALUE) ? name : name + "." + orgName}, true);
+                names[0] = orgName.equals(RRuntime.NAMES_ATTR_EMPTY_VALUE) ? name : name + "." + orgName;
             } else {
                 // multiple values - prepend name to the index of a given value or to the original
                 // name
-                String[] names = new String[v.getLength()];
                 for (int i = 0; i < names.length; i++) {
                     if (name == null) {
                         names[i] = orgNames.getDataAt(i);
@@ -416,11 +412,9 @@ public abstract class Combine extends RBuiltinNode {
                         names[i] = orgName.equals(RRuntime.NAMES_ATTR_EMPTY_VALUE) ? name + (i + 1) : name + "." + orgName;
                     }
                 }
-                newNames = RDataFactory.createStringVector(names, true);
             }
         }
-        v.setNames(newNames);
-        return v;
+        return names;
     }
 
     @NodeChild
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
index ba423dae3cbafc423b481033a8fb9b51cba8348a..fc26c8e3365e813b31cdb70fa6f5e27f2844690e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
@@ -22,7 +22,9 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size;
 import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
@@ -30,9 +32,12 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import java.util.Arrays;
 import java.util.function.Function;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
+import com.oracle.truffle.r.nodes.attributes.PutAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -142,39 +147,44 @@ public abstract class Repeat extends RBuiltinNode {
     }
 
     @Specialization(guards = {"each > 1", "hasNames(x)"})
-    protected RAbstractVector repEachNames(RAbstractVector x, RAbstractIntVector times, int lengthOut, int each) {
+    protected RAbstractVector repEachNames(RAbstractVector x, RAbstractIntVector times, int lengthOut, int each,
+                    @Cached("create()") InitAttributesNode initAttributes,
+                    @Cached("createNames()") PutAttributeNode putNames) {
         if (times.getLength() > 1) {
             errorBranch.enter();
             throw invalidTimes();
         }
         RAbstractVector input = handleEach(x, each);
         RStringVector names = (RStringVector) handleEach(x.getNames(attrProfiles), each);
+        RVector r;
         if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) {
             names = (RStringVector) handleLengthOut(names, lengthOut, false);
-            RVector r = handleLengthOut(input, lengthOut, false);
-            r.setNames(names);
-            return r;
+            r = handleLengthOut(input, lengthOut, false);
         } else {
             names = (RStringVector) handleTimes(names, times, false);
-            RVector r = handleTimes(input, times, false);
-            r.setNames(names);
-            return r;
+            r = handleTimes(input, times, false);
         }
+        putNames.execute(initAttributes.execute(r), names);
+        r.setInternalNames(names);
+        return r;
     }
 
     @Specialization(guards = {"each <= 1", "hasNames(x)"})
-    protected RAbstractVector repNoEachNames(RAbstractVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each) {
+    protected RAbstractVector repNoEachNames(RAbstractVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each,
+                    @Cached("create()") InitAttributesNode initAttributes,
+                    @Cached("createNames()") PutAttributeNode putNames) {
+        RStringVector names;
+        RVector r;
         if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) {
-            RStringVector names = (RStringVector) handleLengthOut(x.getNames(attrProfiles), lengthOut, true);
-            RVector r = handleLengthOut(x, lengthOut, true);
-            r.setNames(names);
-            return r;
+            names = (RStringVector) handleLengthOut(x.getNames(attrProfiles), lengthOut, true);
+            r = handleLengthOut(x, lengthOut, true);
         } else {
-            RStringVector names = (RStringVector) handleTimes(x.getNames(attrProfiles), times, true);
-            RVector r = handleTimes(x, times, true);
-            r.setNames(names);
-            return r;
+            names = (RStringVector) handleTimes(x.getNames(attrProfiles), times, true);
+            r = handleTimes(x, times, true);
         }
+        putNames.execute(initAttributes.execute(r), names);
+        r.setInternalNames(names);
+        return r;
     }
 
     /**
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
index 02dbbaf855144c918ced61076866063bb38648c5..15d687d6799438879e7d85a67c0a1d1ff06a3f96 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessArgumentNode.java
@@ -138,10 +138,7 @@ public final class AccessArgumentNode extends RNode {
 
     private Object doArgument(VirtualFrame frame, Object arg) {
         if (hasDefaultArg) {
-            if (isMissingProfile.profile(arg == RMissing.instance)) {
-                return doArgumentInternal(frame);
-            }
-            if (isEmptyProfile.profile(arg == REmpty.instance)) {
+            if (isMissingProfile.profile(arg == RMissing.instance) || isEmptyProfile.profile(arg == REmpty.instance)) {
                 return doArgumentInternal(frame);
             }
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
index b880d98d8649d7eb23de404bc596058810cec6e5..3a16da932dbf428b19a5f0f79ca1918b07115766 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/BaseWriteVariableNode.java
@@ -51,7 +51,7 @@ abstract class BaseWriteVariableNode extends WriteVariableNode {
     private final ConditionProfile isCurrentProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile isShareableProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile isSharedProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile isRefCountUpdateable = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile isSharedPermanent = ConditionProfile.createBinaryProfile();
 
     private final BranchProfile initialSetKindProfile = BranchProfile.create();
 
@@ -96,11 +96,11 @@ abstract class BaseWriteVariableNode extends WriteVariableNode {
                 if (mode == Mode.COPY) {
                     return rShareable.copy();
                 } else {
-                    if (isRefCountUpdateable.profile(!rShareable.isSharedPermanent())) {
+                    if (!isSharedPermanent.profile(rShareable.isSharedPermanent())) {
                         if (isSuper) {
                             // if non-local assignment, increment conservatively
                             rShareable.incRefCount();
-                        } else if (isSharedProfile.profile(!rShareable.isShared())) {
+                        } else if (!isSharedProfile.profile(rShareable.isShared())) {
                             // don't increment if already shared - will not get "unshared" until
                             // this function exits anyway
                             rShareable.incRefCount();
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
index 6a304222baf4f22bbbf5296aebfe8f0c4d54ef28..8fc53aa127bc467060511104f8de4db53746de28 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java
@@ -28,7 +28,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.vector.CachedExtractVectorNodeFactory.SetNamesNodeGen;
@@ -274,6 +273,8 @@ final class CachedExtractVectorNode extends CachedVectorNode {
     private final ConditionProfile dimNamesNull = ConditionProfile.createBinaryProfile();
     private final ValueProfile foundDimNamesProfile = ValueProfile.createClassProfile();
     private final ConditionProfile selectPositionsProfile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile originalDimNamesPRofile = ConditionProfile.createBinaryProfile();
+    private final ConditionProfile foundNamesProfile = ConditionProfile.createBinaryProfile();
 
     @ExplodeLoop
     private void applyDimensions(RAbstractContainer originalTarget, RVector extractedTarget, int extractedTargetLength, PositionProfile[] positionProfile, Object[] positions) {
@@ -311,9 +312,9 @@ final class CachedExtractVectorNode extends CachedVectorNode {
             if (newDimNames != null) {
                 extractedTarget.setDimNames(RDataFactory.createList(newDimNames));
             }
-        } else if (newDimNames != null && originalDimNames.getLength() > 0) {
+        } else if (newDimNames != null && originalDimNamesPRofile.profile(originalDimNames.getLength() > 0)) {
             RAbstractStringVector foundNames = translateDimNamesToNames(positionProfile, originalDimNames, extractedTargetLength, positions);
-            if (foundNames != null) {
+            if (foundNamesProfile.profile(foundNames != null)) {
                 foundNames = foundDimNamesProfile.profile(foundNames);
                 if (foundNames.getLength() > 0) {
                     metadataApplied.enter();
@@ -323,7 +324,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
         }
     }
 
-    private final BranchProfile droppedDimensionProfile = BranchProfile.create();
+    private final ConditionProfile droppedDimensionProfile = ConditionProfile.createBinaryProfile();
 
     @ExplodeLoop
     private int countDimensions(PositionProfile[] boundsProfile) {
@@ -331,8 +332,7 @@ final class CachedExtractVectorNode extends CachedVectorNode {
             int dimCount = numberOfDimensions;
             for (int i = 0; i < numberOfDimensions; i++) {
                 int selectedPositionsCount = boundsProfile[i].selectedPositionsCount;
-                if (selectedPositionsCount == 1) {
-                    droppedDimensionProfile.enter();
+                if (droppedDimensionProfile.profile(selectedPositionsCount == 1)) {
                     dimCount--;
                 }
             }
@@ -342,6 +342,8 @@ final class CachedExtractVectorNode extends CachedVectorNode {
         }
     }
 
+    private final ConditionProfile srcNamesProfile = ConditionProfile.createBinaryProfile();
+    private final ValueProfile srcNamesValueProfile = ValueProfile.createClassProfile();
     private final ConditionProfile newNamesProfile = ConditionProfile.createBinaryProfile();
 
     @ExplodeLoop
@@ -353,8 +355,8 @@ final class CachedExtractVectorNode extends CachedVectorNode {
                 continue;
             }
 
-            Object srcNames = originalDimNames.getDataAt(currentDimIndex);
-            if (srcNames != RNull.instance) {
+            Object srcNames = srcNamesValueProfile.profile(originalDimNames.getDataAt(currentDimIndex));
+            if (srcNamesProfile.profile(srcNames != RNull.instance)) {
                 Object position = positions[currentDimIndex];
 
                 Object newNames = extractNames((RAbstractStringVector) RRuntime.asAbstractVector(srcNames), new Object[]{position}, new PositionProfile[]{profile}, currentDimIndex,
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java
index bfca64f94be16909d1fb4165563a0acb693e9a32..79c34d928574bbcfd5679d9990cc84cbb7e5746c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyAttributesNode.java
@@ -107,19 +107,20 @@ public abstract class CopyAttributesNode extends RBaseNode {
 
     @Specialization(guards = {"leftLength == rightLength", "containsMetadata(left, attrLeftProfiles) || containsMetadata(right, attrRightProfiles)"})
     protected RAbstractVector copySameLength(RAbstractVector target, RAbstractVector left, @SuppressWarnings("unused") int leftLength, RAbstractVector right,
-                    @SuppressWarnings("unused") int rightLength, //
-                    @Cached("create()") CopyOfRegAttributesNode copyOfRegLeft, //
-                    @Cached("create()") CopyOfRegAttributesNode copyOfRegRight, //
-                    @Cached("createDim()") RemoveAttributeNode removeDim, //
-                    @Cached("createDimNames()") RemoveAttributeNode removeDimNames, //
-                    @Cached("create()") InitAttributesNode initAttributes, //
-                    @Cached("createNames()") PutAttributeNode putNames, //
-                    @Cached("createDim()") PutAttributeNode putDim, //
-                    @Cached("create()") BranchProfile leftHasDimensions, //
-                    @Cached("create()") BranchProfile rightHasDimensions, //
-                    @Cached("create()") BranchProfile noDimensions, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasNamesLeft, //
-                    @Cached("createBinaryProfile()") ConditionProfile hasNamesRight, //
+                    @SuppressWarnings("unused") int rightLength,
+                    @Cached("create()") CopyOfRegAttributesNode copyOfRegLeft,
+                    @Cached("create()") CopyOfRegAttributesNode copyOfRegRight,
+                    @Cached("createBinaryProfile()") ConditionProfile hasAttributes,
+                    @Cached("createDim()") RemoveAttributeNode removeDim,
+                    @Cached("createDimNames()") RemoveAttributeNode removeDimNames,
+                    @Cached("create()") InitAttributesNode initAttributes,
+                    @Cached("createNames()") PutAttributeNode putNames,
+                    @Cached("createDim()") PutAttributeNode putDim,
+                    @Cached("create()") BranchProfile leftHasDimensions,
+                    @Cached("create()") BranchProfile rightHasDimensions,
+                    @Cached("create()") BranchProfile noDimensions,
+                    @Cached("createBinaryProfile()") ConditionProfile hasNamesLeft,
+                    @Cached("createBinaryProfile()") ConditionProfile hasNamesRight,
                     @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
         if (LOG) {
             log("copyAttributes: ==");
@@ -141,7 +142,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
             if (newDimensions == null) {
                 noDimensions.enter();
                 RAttributes attributes = result.getAttributes();
-                if (attributes != null) {
+                if (hasAttributes.profile(attributes != null)) {
                     removeDim.execute(attributes);
                     removeDimNames.execute(attributes);
                     result.setInternalDimNames(null);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java
index b066be22af2ab3675b97b82ef6d48ff6029d2223..de60064a28a74110e61b45178f375df86982aeb0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.attributes;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RAttributes;
 import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute;
@@ -37,6 +38,8 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  */
 public abstract class CopyOfRegAttributesNode extends RBaseNode {
 
+    private final ConditionProfile sizeOneProfile = ConditionProfile.createBinaryProfile();
+
     public abstract void execute(RAbstractVector source, RVector target);
 
     public static CopyOfRegAttributesNode create() {
@@ -60,9 +63,9 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
         // nothing to do
     }
 
-    protected static final boolean onlyDimAttribute(RAbstractVector source) {
+    protected final boolean onlyDimAttribute(RAbstractVector source) {
         RAttributes attributes = source.getAttributes();
-        return attributes != null && attributes.size() == 1 && attributes.getNameAtIndex(0) == RRuntime.DIM_ATTR_KEY;
+        return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && attributes.getNameAtIndex(0) == RRuntime.DIM_ATTR_KEY;
     }
 
     @SuppressWarnings("unused")
@@ -71,9 +74,9 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
         // nothing to do
     }
 
-    protected static final boolean onlyNamesAttribute(RAbstractVector source) {
+    protected final boolean onlyNamesAttribute(RAbstractVector source) {
         RAttributes attributes = source.getAttributes();
-        return attributes != null && attributes.size() == 1 && attributes.getNameAtIndex(0) == RRuntime.NAMES_ATTR_KEY;
+        return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && attributes.getNameAtIndex(0) == RRuntime.NAMES_ATTR_KEY;
     }
 
     @SuppressWarnings("unused")
@@ -82,9 +85,9 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
         // nothing to do
     }
 
-    protected static final boolean onlyClassAttribute(RAbstractVector source) {
+    protected final boolean onlyClassAttribute(RAbstractVector source) {
         RAttributes attributes = source.getAttributes();
-        return attributes != null && attributes.size() == 1 && attributes.getNameAtIndex(0) == RRuntime.CLASS_ATTR_KEY;
+        return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && attributes.getNameAtIndex(0) == RRuntime.CLASS_ATTR_KEY;
     }
 
     @Specialization(guards = "onlyClassAttribute(source)")
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 ee4d814f981084f26fe209474fdbb1a721e4da9b..f85dd66cf16c803f762481530663d5a3d08f5703 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
@@ -839,7 +839,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
             FormalArguments formals = root.getFormalArguments();
             if (root instanceof RBuiltinRootNode) {
                 RBuiltinRootNode builtinRoot = (RBuiltinRootNode) root;
-                return new BuiltinCallNode(RBuiltinNode.inline(builtinRoot.getBuiltin(), null), builtinRoot.getBuiltin(), formals, originalCall);
+                return new BuiltinCallNode(RBuiltinNode.inline(builtinRoot.getBuiltin(), null), builtinRoot.getBuiltin(), formals, originalCall, explicitArgs);
             } else {
                 return new DispatchedCallNode(cachedTarget, originalCall);
             }
@@ -928,36 +928,54 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
     private static final class BuiltinCallNode extends LeafCallNode {
 
         @Child private RBuiltinNode builtin;
-        @Child private PromiseCheckHelperNode promiseHelper;
+        @Child private PromiseCheckHelperNode varArgsPromiseHelper;
+        @Children private final PromiseHelperNode[] promiseHelpers;
         @Children private final CastNode[] casts;
         @Child private SetVisibilityNode visibility = SetVisibilityNode.create();
 
-        private final BranchProfile emptyProfile = BranchProfile.create();
-        private final BranchProfile varArgsProfile = BranchProfile.create();
-        private final ConditionProfile wrapProfile = ConditionProfile.createBinaryProfile();
+        // not using profiles to save overhead
+        private final boolean[] argEmptySeen;
+        private final boolean[] varArgSeen;
+        private final boolean[] nonWrapSeen;
+        private final boolean[] wrapSeen;
+
         private final FormalArguments formals;
         private final RBuiltinDescriptor builtinDescriptor;
+        private boolean explicitArgs;
 
-        BuiltinCallNode(RBuiltinNode builtin, RBuiltinDescriptor builtinDescriptor, FormalArguments formalArguments, RCallNode originalCall) {
+        BuiltinCallNode(RBuiltinNode builtin, RBuiltinDescriptor builtinDescriptor, FormalArguments formalArguments, RCallNode originalCall, boolean explicitArgs) {
             super(originalCall);
             this.builtin = builtin;
             this.builtinDescriptor = builtinDescriptor;
+            this.explicitArgs = explicitArgs;
             this.casts = builtin.getCasts();
             this.formals = formalArguments;
+            promiseHelpers = new PromiseHelperNode[formals.getLength()];
+            argEmptySeen = new boolean[formals.getLength()];
+            varArgSeen = new boolean[formals.getLength()];
+            nonWrapSeen = new boolean[formals.getLength()];
+            wrapSeen = new boolean[formals.getLength()];
         }
 
         @ExplodeLoop
         public Object[] castArguments(VirtualFrame frame, Object[] args) {
             int argCount = formals.getLength();
+            int varArgIndex = formals.getSignature().getVarArgIndex();
             Object[] result = new Object[argCount];
             for (int i = 0; i < argCount; i++) {
                 Object arg = args[i];
-                if (arg == REmpty.instance) {
-                    emptyProfile.enter();
+                if (explicitArgs && arg == REmpty.instance) {
+                    if (!argEmptySeen[i]) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        argEmptySeen[i] = true;
+                    }
                     arg = formals.getInternalDefaultArgumentAt(i);
                 }
-                if (arg instanceof RArgsValuesAndNames) {
-                    varArgsProfile.enter();
+                if (varArgIndex == i && arg instanceof RArgsValuesAndNames) {
+                    if (!varArgSeen[i]) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        varArgSeen[i] = true;
+                    }
                     RArgsValuesAndNames varArgs = (RArgsValuesAndNames) arg;
                     if (builtinDescriptor.evaluatesArg(i)) {
                         forcePromises(frame, varArgs);
@@ -967,12 +985,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                 } else {
                     if (builtinDescriptor.evaluatesArg(i)) {
                         if (arg instanceof RPromise) {
-                            if (promiseHelper == null) {
+                            if (promiseHelpers[i] == null) {
                                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                                promiseHelper = insert(new PromiseCheckHelperNode());
+                                promiseHelpers[i] = insert(new PromiseHelperNode());
                             }
-                            arg = promiseHelper.checkEvaluate(frame, arg);
-
+                            arg = promiseHelpers[i].evaluate(frame, (RPromise) arg);
                         }
                         if (i < casts.length && casts[i] != null) {
                             assert builtinDescriptor.evaluatesArg(i);
@@ -980,7 +997,16 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
                         }
                     } else {
                         assert casts.length <= i || casts[i] == null : "no casts allowed on non-evaluated arguments";
-                        if (wrapProfile.profile(!(arg instanceof RPromise || arg instanceof RMissing))) {
+                        if (arg instanceof RPromise || arg instanceof RMissing) {
+                            if (!nonWrapSeen[i]) {
+                                CompilerDirectives.transferToInterpreterAndInvalidate();
+                                nonWrapSeen[i] = true;
+                            }
+                        } else {
+                            if (!wrapSeen[i]) {
+                                CompilerDirectives.transferToInterpreterAndInvalidate();
+                                wrapSeen[i] = true;
+                            }
                             arg = createPromise(arg);
                         }
                     }
@@ -993,11 +1019,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS
         private void forcePromises(VirtualFrame frame, RArgsValuesAndNames varArgs) {
             Object[] array = varArgs.getArguments();
             for (int i = 0; i < array.length; i++) {
-                if (promiseHelper == null) {
+                if (varArgsPromiseHelper == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    promiseHelper = insert(new PromiseCheckHelperNode());
+                    varArgsPromiseHelper = insert(new PromiseCheckHelperNode());
                 }
-                array[i] = promiseHelper.checkEvaluate(frame, array[i]);
+                array[i] = varArgsPromiseHelper.checkEvaluate(frame, array[i]);
             }
         }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
index 9cb4f0d2939053290bf23227eea5ed16281774fb..90437a0a43800871bbf1f9b5a22fe67c73bbe10d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.primitive;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
@@ -73,7 +74,7 @@ public final class BinaryMapNode extends RBaseNode {
     private final ConditionProfile maxLengthProfile;
     private final ConditionProfile leftIsNAProfile = ConditionProfile.createBinaryProfile();
     private final ConditionProfile rightIsNAProfile = ConditionProfile.createBinaryProfile();
-    private final BranchProfile seenEmpty = BranchProfile.create();
+    private final ConditionProfile seenEmpty = ConditionProfile.createBinaryProfile();
     private final ConditionProfile shareLeft;
     private final ConditionProfile shareRight;
     private final RType argumentType;
@@ -229,16 +230,16 @@ public final class BinaryMapNode extends RBaseNode {
     private Object applyVectorized(RAbstractVector left, RAbstractVector leftCast, int leftLength, RAbstractVector right, RAbstractVector rightCast, int rightLength) {
         if (mayContainMetadata && (dimensionsProfile.profile(left.hasDimensions() && right.hasDimensions()))) {
             if (differentDimensions(left, right)) {
+                CompilerDirectives.transferToInterpreter();
                 throw RError.error(this, RError.Message.NON_CONFORMABLE_ARRAYS);
             }
         }
 
-        if (leftLength == 0 || rightLength == 0) {
+        if (seenEmpty.profile(leftLength == 0 || rightLength == 0)) {
             /*
              * It is safe to skip attribute handling here as they are never copied if length is 0 of
              * either side. Note that dimension check still needs to be performed.
              */
-            seenEmpty.enter();
             return resultType.getEmpty();
         }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
index 9132ef16228f3fa65e5b00ad550e40a32032a94e..7c3def09aa07d436b25b8cdbfdc7a4c5f13bff1a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
@@ -46,8 +46,6 @@ public final class ArgumentsSignature implements Iterable<String> {
     public static final String VARARG_NAME = "...";
     public static final int NO_VARARG = -1;
 
-    private static final String VARARG_GETTER_PREFIX = "..";
-
     @CompilationFinal private static final ArgumentsSignature[] EMPTY_SIGNATURES = new ArgumentsSignature[32];
     public static final ArgumentsSignature INVALID_SIGNATURE = new ArgumentsSignature(new String[]{"<<invalid>>"});
 
@@ -78,7 +76,7 @@ public final class ArgumentsSignature implements Iterable<String> {
     @CompilationFinal private final String[] names;
     @CompilationFinal private final int[] varArgIndexes;
     @CompilationFinal private final boolean[] isVarArg;
-    @CompilationFinal private final boolean[] isVarArgGetter;
+    private final int varArgIndex;
     private final int nonNullCount;
 
     private ArgumentsSignature(String[] names) {
@@ -88,7 +86,6 @@ public final class ArgumentsSignature implements Iterable<String> {
         int index = NO_VARARG;
         int count = 0;
         this.isVarArg = new boolean[names.length];
-        this.isVarArgGetter = new boolean[names.length];
         for (int i = 0; i < names.length; i++) {
             String name = names[i];
             if (name != null) {
@@ -98,8 +95,6 @@ public final class ArgumentsSignature implements Iterable<String> {
                     if (index != NO_VARARG) {
                         index = i;
                     }
-                } else if (name.startsWith(VARARG_GETTER_PREFIX)) {
-                    this.isVarArgGetter[i] = true;
                 }
             }
         }
@@ -110,6 +105,7 @@ public final class ArgumentsSignature implements Iterable<String> {
                 varArgIndexes[pos++] = i;
             }
         }
+        this.varArgIndex = varArgIndexes.length == 0 ? NO_VARARG : varArgIndexes[0];
     }
 
     public boolean isEmpty() {
@@ -126,7 +122,7 @@ public final class ArgumentsSignature implements Iterable<String> {
 
     public int getVarArgIndex() {
         assert varArgIndexes.length <= 1 : "cannot ask for _the_ vararg index if there are multiple varargs";
-        return varArgIndexes.length == 0 ? NO_VARARG : varArgIndexes[0];
+        return varArgIndex;
     }
 
     public int getVarArgCount() {
@@ -207,7 +203,7 @@ public final class ArgumentsSignature implements Iterable<String> {
      * methods {@link #isVarArgsIndex(long)}, {@link #extractVarArgsArgumentIndex(long)} and
      * {@link #extractVarArgsArgumentIndex(long)} to access the data packed in the {@code long}
      * value. This method also removes arguments that are marked as 'unmatched' in the signature.
-     * 
+     *
      * @param argListSize length of the result -- sum of lengths of all varargs contained within
      *            varArgSignatures minus any unmatched arguments.
      */