diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
index 470d1ba4cf21f2e3a72db08dce47ccf36bf590a3..3d5affd9c07cf9595deccc65495360b17ca5a991 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java
@@ -24,6 +24,7 @@ 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.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -132,10 +133,10 @@ public abstract class APerm extends RBuiltinNode {
 
     @Specialization
     protected RAbstractVector aPerm(RAbstractVector vector, RAbstractStringVector permVector, byte resize,
-                    @Cached("create()") RAttributeProfiles dimNamesProfile,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
-                    @Cached("create()") SetDimAttributeNode setDimsNode) {
-        RList dimNames = vector.getDimNames(dimNamesProfile);
+                    @Cached("create()") SetDimAttributeNode setDimsNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (dimNames == null) {
             // TODO: this error is reported after IS_OF_WRONG_LENGTH in GnuR
             errorProfile.enter();
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 ce9e8aef90d9a161d4cce2e8638082cb241b0c2d..8ae71563084a6c71e6e6816ee8a0e49b4dfc7417 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
@@ -37,6 +37,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
@@ -174,7 +175,7 @@ public abstract class Bind extends RBaseNode {
     }
 
     private Object bindInternal(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast, SetDimAttributeNode setDimNode,
-                    SetDimNamesAttributeNode setDimNamesNode) {
+                    SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getDimNamesNode) {
         ArgumentsSignature signature = promiseArgs.getSignature();
         String[] vecNames = nullNamesProfile.profile(signature.getNonNullCount() == 0) ? null : new String[signature.getLength()];
         RAbstractVector[] vectors = new RAbstractVector[args.length];
@@ -230,9 +231,9 @@ public abstract class Bind extends RBaseNode {
             }
         }
         if (type == BindType.cbind) {
-            return genericCBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode);
+            return genericCBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode, getDimNamesNode);
         } else {
-            return genericRBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode);
+            return genericRBind(promiseArgs, vectors, complete, vecNames, naCheck.neverSeenNA(), deparseLevel, setDimNode, setDimNamesNode, getDimNamesNode);
         }
     }
 
@@ -240,48 +241,54 @@ public abstract class Bind extends RBaseNode {
     protected Object allLogical(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @Cached("create()") CastLogicalNode cast,
                     @Cached("create()") SetDimAttributeNode setDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization(guards = {"precedence == INT_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allInt(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @Cached("create()") CastIntegerNode cast,
                     @Cached("create()") SetDimAttributeNode setDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization(guards = {"precedence == DOUBLE_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allDouble(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @Cached("create()") CastDoubleNode cast,
                     @Cached("create()") SetDimAttributeNode setDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization(guards = {"precedence == STRING_PRECEDENCE", "args.length> 1", "!isDataFrame(args)"})
     protected Object allString(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @Cached("create()") CastStringNode cast,
                     @Cached("create()") SetDimAttributeNode setDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization(guards = {"precedence == COMPLEX_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allComplex(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @Cached("create()") CastComplexNode cast,
                     @Cached("create()") SetDimAttributeNode setDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, true, setDimNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization(guards = {"precedence == LIST_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"})
     protected Object allList(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, //
                     @Cached("create()") CastListNode cast,
                     @Cached("create()") SetDimAttributeNode setDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return bindInternal(deparseLevel, args, promiseArgs, cast, false, setDimNode, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        return bindInternal(deparseLevel, args, promiseArgs, cast, false, setDimNode, setDimNamesNode, getDimNamesNode);
     }
 
     /**
@@ -292,11 +299,11 @@ public abstract class Bind extends RBaseNode {
      * @param dimLength
      * @return dimnames
      */
-    protected Object getDimResultNamesFromElements(RAbstractVector vec, int dimLength, int dimInd) {
+    protected Object getDimResultNamesFromElements(RAbstractVector vec, int dimLength, int dimInd, GetDimNamesAttributeNode getDimNamesNode) {
         Object firstDimResultNames = RNull.instance;
         Object firstDimNames = RNull.instance;
         if (vec.isMatrix()) {
-            RList vecDimNames = vec.getDimNames(attrProfiles);
+            RList vecDimNames = getDimNamesNode.getDimNames(vec);
             if (vecDimNames != null) {
                 firstDimNames = vecDimNames.getDataAt(dimInd);
             }
@@ -320,11 +327,10 @@ public abstract class Bind extends RBaseNode {
      * by deparsing.
      */
     protected int getDimResultNamesFromVectors(RArgsValuesAndNames promiseArgs, RAbstractVector vec, String[] argNames, int resDim, int oldInd, int vecInd, int deparseLevel,
-                    String[] dimNamesArray,
-                    int dimNamesInd) {
+                    String[] dimNamesArray, int dimNamesInd, GetDimNamesAttributeNode getDimNamesNode) {
         int ind = oldInd;
         if (vec.isMatrix()) {
-            RList vecDimNames = vec.getDimNames(attrProfiles);
+            RList vecDimNames = getDimNamesNode.getDimNames(vec);
             if (vecDimNames != null) {
                 Object resDimNames = vecDimNames.getDataAt(dimNamesInd);
                 if (resDimNames != RNull.instance) {
@@ -506,7 +512,7 @@ public abstract class Bind extends RBaseNode {
     }
 
     public RVector<?> genericCBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel,
-                    SetDimAttributeNode setDimNode, SetDimNamesAttributeNode setDimNamesNode) {
+                    SetDimAttributeNode setDimNode, SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getDimNamesNode) {
 
         int[] resultDimensions = new int[2];
         int[] secondDims = new int[vectors.length];
@@ -523,11 +529,11 @@ public abstract class Bind extends RBaseNode {
             RAbstractVector vec = vectorProfile.profile(vectors[i]);
             if (rowDimResultNames == RNull.instance) {
                 // get the first valid names value
-                rowDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[0], 0);
+                rowDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[0], 0, getDimNamesNode);
             }
 
             // compute dimnames for the second dimension
-            int newColInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, secondDims[i], colInd, i, deparseLevel, colDimNamesArray, 1);
+            int newColInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, secondDims[i], colInd, i, deparseLevel, colDimNamesArray, 1, getDimNamesNode);
             if (newColInd < 0) {
                 colInd = -newColInd;
             } else {
@@ -588,7 +594,7 @@ public abstract class Bind extends RBaseNode {
     }
 
     public RVector<?> genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel,
-                    SetDimAttributeNode setDimNode, SetDimNamesAttributeNode setDimNamesNode) {
+                    SetDimAttributeNode setDimNode, SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getDimNamesNode) {
 
         int[] resultDimensions = new int[2];
         int[] firstDims = new int[vectors.length];
@@ -604,11 +610,11 @@ public abstract class Bind extends RBaseNode {
             RAbstractVector vec = vectorProfile.profile(vectors[i]);
             if (colDimResultNames == RNull.instance) {
                 // get the first valid names value
-                colDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[1], 1);
+                colDimResultNames = getDimResultNamesFromElements(vec, resultDimensions[1], 1, getDimNamesNode);
             }
 
             // compute dimnames for the second dimension
-            int newRowInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, firstDims[i], rowInd, i, deparseLevel, rowDimNamesArray, 0);
+            int newRowInd = getDimResultNamesFromVectors(promiseArgs, vec, vecNames, firstDims[i], rowInd, i, deparseLevel, rowDimNamesArray, 0, getDimNamesNode);
             if (newRowInd < 0) {
                 rowInd = -newRowInd;
             } else {
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 9f291c1c2e8ce95c266b1a527d213a0bc696c641..33132b9ae090b56cb9a8cb40d4d21af27421c254 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
@@ -47,6 +47,7 @@ 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.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.CombineNodeGen.CombineInputCastNodeGen;
@@ -454,6 +455,7 @@ public abstract class Combine extends RBuiltinNode {
     protected abstract static class CombineInputCast extends RNode {
 
         private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
+        @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
         public abstract Object execute(Object operand);
 
@@ -492,7 +494,7 @@ public abstract class Combine extends RBuiltinNode {
         }
 
         protected boolean needsCopy(RAbstractVector vector) {
-            return vector.getAttributes() != null || vector.getNames(attrProfiles) != null || vector.getDimNames(attrProfiles) != null;
+            return vector.getAttributes() != null || vector.getNames(attrProfiles) != null || getDimNamesNode.getDimNames(vector) != null;
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
index dec2884830fda1f105f25294440f528c9eadba3b..9c6e521f08bfa375abdeec6ab6003d53c8d06ab0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 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;
@@ -68,14 +69,16 @@ public abstract class Crossprod extends RBuiltinNode {
     protected RDoubleVector crossprod(RAbstractDoubleVector x, RAbstractDoubleVector y,
                     @Cached("create()") GetDimAttributeNode getXDimsNode,
                     @Cached("create()") GetDimAttributeNode getYDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
         int[] xDims = getXDimsNode.getDimensions(x);
         int[] yDims = getYDimsNode.getDimensions(y);
         int xRows = xDims[0];
         int xCols = xDims[1];
         int yRows = yDims[0];
         int yCols = yDims[1];
-        return matMult.doubleMatrixMultiply(x, y, xCols, xRows, yRows, yCols, xRows, 1, 1, yRows, false, setDimNamesNode);
+        return matMult.doubleMatrixMultiply(x, y, xCols, xRows, yRows, yCols, xRows, 1, 1, yRows, false, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     private static RDoubleVector mirror(RDoubleVector result, GetDimAttributeNode getResultDimsNode) {
@@ -108,11 +111,13 @@ public abstract class Crossprod extends RBuiltinNode {
     protected RDoubleVector crossprodDoubleMatrix(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
                     @Cached("create()") GetDimAttributeNode getResultDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
         int[] xDims = getDimsNode.getDimensions(x);
         int xRows = xDims[0];
         int xCols = xDims[1];
-        return mirror(matMult.doubleMatrixMultiply(x, x, xCols, xRows, xRows, xCols, xRows, 1, 1, xRows, true, setDimNamesNode), getResultDimsNode);
+        return mirror(matMult.doubleMatrixMultiply(x, x, xCols, xRows, xRows, xCols, xRows, 1, 1, xRows, true, setDimNamesNode, getADimNamesNode, getBDimNamesNode), getResultDimsNode);
     }
 
     @Specialization
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
index 17661779644a7b819009377f238888db6a8a9fde..5a89f5ffb2050b88427f11c543ec02f997502d5f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DimNames.java
@@ -26,8 +26,10 @@ 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;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
@@ -38,7 +40,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 @RBuiltin(name = "dimnames", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE)
 public abstract class DimNames extends RBuiltinNode {
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final ConditionProfile nullProfile = ConditionProfile.createBinaryProfile();
 
     @Specialization(guards = "!isRAbstractContainer(operand)")
@@ -47,8 +48,8 @@ public abstract class DimNames extends RBuiltinNode {
     }
 
     @Specialization
-    protected Object getDimNames(RAbstractContainer container) {
-        RList names = container.getDimNames(attrProfiles);
+    protected Object getDimNames(RAbstractContainer container, @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
+        RList names = getDimNamesNode.getDimNames(container);
         return nullProfile.profile(names == null) ? RNull.instance : names;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
index b968a3e2d1faeb53f2479913e35f9e4f71f50f29..ce99c5869b2ae21b6e0942ff6ed6458f534c1268 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Drop.java
@@ -30,6 +30,7 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -54,7 +55,8 @@ public abstract class Drop extends RBuiltinNode {
     protected RAbstractVector doDrop(RAbstractVector x,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
                     @Cached("create()") SetDimAttributeNode setDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimsNamseNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimsNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimsNamesNode) {
         int[] dims = getDimsNode.getDimensions(x);
         if (nullDimensions.profile(dims == null)) {
             return x;
@@ -75,14 +77,14 @@ public abstract class Drop extends RBuiltinNode {
             @SuppressWarnings("unused")
             RAbstractVector r = x.copy();
             setDimsNode.setDimensions(x, null);
-            setDimsNamseNode.setDimNames(x, null);
+            setDimsNamesNode.setDimNames(x, null);
             x.setNames(null);
             return x;
         }
 
         // the result is vector
         if (resultIsVector.profile(newDimsLength <= 1)) {
-            return toVector(x, lastNonOneIndex, setDimsNode);
+            return toVector(x, lastNonOneIndex, setDimsNode, getDimsNamesNode);
         }
 
         // else: the result will be a matrix, copy non-1 dimensions
@@ -98,7 +100,7 @@ public abstract class Drop extends RBuiltinNode {
         setDimsNode.setDimensions(result, newDims);
 
         // if necessary, copy corresponding dimnames
-        RList oldDimNames = x.getDimNames(dimNamesAttrProfile);
+        RList oldDimNames = getDimsNamesNode.getDimNames(x);
         if (noDimNamesProfile.profile(oldDimNames != null)) {
             newDimsIdx = 0;
             Object[] newDimNames = new Object[newDimsLength];
@@ -107,9 +109,9 @@ public abstract class Drop extends RBuiltinNode {
                     newDimNames[newDimsIdx++] = oldDimNames.getDataAt(i);
                 }
             }
-            setDimsNamseNode.setDimNames(result, RDataFactory.createList(newDimNames));
+            setDimsNamesNode.setDimNames(result, RDataFactory.createList(newDimNames));
         } else {
-            setDimsNamseNode.setDimNames(result, null);
+            setDimsNamesNode.setDimNames(result, null);
         }
 
         return result;
@@ -119,12 +121,12 @@ public abstract class Drop extends RBuiltinNode {
      * Handles the case when result is just a vector. The only catch is that we might have to copy
      * corresponding index from dimnames to names attribute of the new vector.
      */
-    private RAbstractVector toVector(RAbstractVector x, int nonOneIndex, SetDimAttributeNode setDimsNode) {
+    private RAbstractVector toVector(RAbstractVector x, int nonOneIndex, SetDimAttributeNode setDimsNode, GetDimNamesAttributeNode getDimNamesNode) {
         RAbstractVector result = x.copy(); // share?
         setDimsNode.setDimensions(result, null);
 
         // copy dimnames to names if possible
-        RList dimNames = x.getDimNames(dimNamesAttrProfile);
+        RList dimNames = getDimNamesNode.getDimNames(x);
         if (noDimNamesProfile.profile(dimNames != null) && nonOneIndex < dimNames.getLength()) {
             result.setNames(ensureStringVector(dimNames.getDataAt(nonOneIndex)));
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
index 59818d65964a964481c7164c9c0ce9c0064e01f4..8730d78a9e45251ddf395d7c811916f4b193f7fa 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java
@@ -33,6 +33,7 @@ import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -79,12 +80,13 @@ public abstract class IsNA extends RBuiltinNode {
     @Specialization
     protected RLogicalVector isNA(RAbstractIntVector vector,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         byte[] resultVector = new byte[vector.getLength()];
         for (int i = 0; i < vector.getLength(); i++) {
             resultVector[i] = RRuntime.asLogical(RRuntime.isNA(vector.getDataAt(i)));
         }
-        return createResult(resultVector, vector, getDimsNode, setDimNamesNode);
+        return createResult(resultVector, vector, getDimsNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization
@@ -95,24 +97,26 @@ public abstract class IsNA extends RBuiltinNode {
     @Specialization
     protected RLogicalVector isNA(RAbstractDoubleVector vector,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         byte[] resultVector = new byte[vector.getLength()];
         for (int i = 0; i < vector.getLength(); i++) {
             resultVector[i] = RRuntime.asLogical(RRuntime.isNAorNaN(vector.getDataAt(i)));
         }
-        return createResult(resultVector, vector, getDimsNode, setDimNamesNode);
+        return createResult(resultVector, vector, getDimsNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization
     protected RLogicalVector isNA(RComplexVector vector,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         byte[] resultVector = new byte[vector.getLength()];
         for (int i = 0; i < vector.getLength(); i++) {
             RComplex complex = vector.getDataAt(i);
             resultVector[i] = RRuntime.asLogical(RRuntime.isNA(complex));
         }
-        return createResult(resultVector, vector, getDimsNode, setDimNamesNode);
+        return createResult(resultVector, vector, getDimsNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization
@@ -123,12 +127,13 @@ public abstract class IsNA extends RBuiltinNode {
     @Specialization
     protected RLogicalVector isNA(RStringVector vector,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         byte[] resultVector = new byte[vector.getLength()];
         for (int i = 0; i < vector.getLength(); i++) {
             resultVector[i] = RRuntime.asLogical(RRuntime.isNA(vector.getDataAt(i)));
         }
-        return createResult(resultVector, vector, getDimsNode, setDimNamesNode);
+        return createResult(resultVector, vector, getDimsNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization
@@ -165,12 +170,13 @@ public abstract class IsNA extends RBuiltinNode {
     @Specialization
     protected RLogicalVector isNA(RLogicalVector vector,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         byte[] resultVector = new byte[vector.getLength()];
         for (int i = 0; i < vector.getLength(); i++) {
             resultVector[i] = (RRuntime.isNA(vector.getDataAt(i)) ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE);
         }
-        return createResult(resultVector, vector, getDimsNode, setDimNamesNode);
+        return createResult(resultVector, vector, getDimsNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization
@@ -186,12 +192,13 @@ public abstract class IsNA extends RBuiltinNode {
     @Specialization
     protected RLogicalVector isNA(RRawVector vector,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         byte[] resultVector = new byte[vector.getLength()];
         for (int i = 0; i < vector.getLength(); i++) {
             resultVector[i] = RRuntime.LOGICAL_FALSE;
         }
-        return createResult(resultVector, vector, getDimsNode, setDimNamesNode);
+        return createResult(resultVector, vector, getDimsNode, setDimNamesNode, getDimNamesNode);
     }
 
     @Specialization
@@ -208,9 +215,10 @@ public abstract class IsNA extends RBuiltinNode {
         return RRuntime.LOGICAL_FALSE;
     }
 
-    private RLogicalVector createResult(byte[] data, RAbstractVector originalVector, GetDimAttributeNode getDimsNode, SetDimNamesAttributeNode setDimNamesNode) {
+    private RLogicalVector createResult(byte[] data, RAbstractVector originalVector, GetDimAttributeNode getDimsNode, SetDimNamesAttributeNode setDimNamesNode,
+                    GetDimNamesAttributeNode getDimNamesNode) {
         RLogicalVector result = RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR, getDimsNode.getDimensions(originalVector), originalVector.getNames(attrProfiles));
-        RList dimNames = originalVector.getDimNames(attrProfiles);
+        RList dimNames = getDimNamesNode.getDimNames(originalVector);
         if (nullDimNamesProfile.profile(dimNames != null)) {
             setDimNamesNode.setDimNames(result, dimNames);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index 7fa39325e78b94f53a5382f965f586124fae1cb2..da2e58590d3677dddd566d2df622a52d776b94c0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
@@ -561,7 +562,8 @@ public class LaFunctions {
                         @Cached("create()") GetDimAttributeNode getADimsNode,
                         @Cached("create()") GetDimAttributeNode getBinDimsNode,
                         @Cached("create()") SetDimAttributeNode setBDimsNode,
-                        @Cached("create()") SetDimNamesAttributeNode setBDimNamesNode) {
+                        @Cached("create()") SetDimNamesAttributeNode setBDimNamesNode,
+                        @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
             int[] aDims = getADimsNode.getDimensions(a);
             int n = aDims[0];
             if (n == 0) {
@@ -571,7 +573,7 @@ public class LaFunctions {
             if (n2 != n) {
                 throw RError.error(this, RError.Message.MUST_BE_SQUARE, "a", n, n2);
             }
-            RList aDn = a.getDimNames(attrProfiles);
+            RList aDn = getDimNamesNode.getDimNames(a);
             int p;
             double[] bData;
             RDoubleVector b;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
index 85ca79cd914681006c88b73b439dec0a42895154..8a2be573ef29b4703301dfd9795c5000b48e1a27 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.binary.BinaryMapArithmeticFunctionNode;
@@ -74,8 +75,6 @@ public abstract class MatMult extends RBuiltinNode {
     private final ConditionProfile notOneRow = ConditionProfile.createBinaryProfile();
     private final ConditionProfile notOneColumn = ConditionProfile.createBinaryProfile();
 
-    private final RAttributeProfiles aDimAttributeProfile = RAttributeProfiles.create();
-    private final RAttributeProfiles bDimAttributeProfile = RAttributeProfiles.create();
     private final ConditionProfile noDimAttributes = ConditionProfile.createBinaryProfile();
 
     @Child protected GetDimAttributeNode getADimsNode = GetDimAttributeNode.create();
@@ -142,8 +141,9 @@ public abstract class MatMult extends RBuiltinNode {
     private final BranchProfile incompleteProfile = BranchProfile.create();
     @CompilationFinal private boolean seenLargeMatrix;
 
-    private RDoubleVector doubleMatrixMultiply(RAbstractDoubleVector a, RAbstractDoubleVector b, int aRows, int aCols, int bRows, int bCols, SetDimNamesAttributeNode setDimNamesNode) {
-        return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, 1, aRows, 1, bRows, false, setDimNamesNode);
+    private RDoubleVector doubleMatrixMultiply(RAbstractDoubleVector a, RAbstractDoubleVector b, int aRows, int aCols, int bRows, int bCols, SetDimNamesAttributeNode setDimNamesNode,
+                    GetDimNamesAttributeNode getADimNamesNode, GetDimNamesAttributeNode getBDimNamesNode) {
+        return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, 1, aRows, 1, bRows, false, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     /**
@@ -164,7 +164,7 @@ public abstract class MatMult extends RBuiltinNode {
      * @return the result vector
      */
     public RDoubleVector doubleMatrixMultiply(RAbstractDoubleVector a, RAbstractDoubleVector b, int aRows, int aCols, int bRows, int bCols, int aRowStride, int aColStride, int bRowStride,
-                    int bColStride, boolean mirrored, SetDimNamesAttributeNode setDimNamesNode) {
+                    int bColStride, boolean mirrored, SetDimNamesAttributeNode setDimNamesNode, GetDimNamesAttributeNode getADimNamesNode, GetDimNamesAttributeNode getBDimNamesNode) {
         if (aCols != bRows) {
             errorProfile.enter();
             throw RError.error(this, RError.Message.NON_CONFORMABLE_ARGS);
@@ -216,8 +216,8 @@ public abstract class MatMult extends RBuiltinNode {
         }
 
         RDoubleVector resultVec = RDataFactory.createDoubleVector(result, complete, new int[]{aRows, bCols});
-        RList aDimNames = a.getDimNames(aDimAttributeProfile);
-        RList bDimNames = b.getDimNames(bDimAttributeProfile);
+        RList aDimNames = getADimNamesNode.getDimNames(a);
+        RList bDimNames = getBDimNamesNode.getDimNames(b);
         if (!promoteDimNames || noDimAttributes.profile(aDimNames == null && bDimNames == null)) {
             return resultVec;
         }
@@ -275,12 +275,14 @@ public abstract class MatMult extends RBuiltinNode {
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
         if (aIsMatrix.profile(a.isMatrix())) {
             if (bIsMatrix.profile(b.isMatrix())) {
                 int[] aDimensions = getADimsNode.getDimensions(a);
                 int[] bDimensions = getBDimsNode.getDimensions(b);
-                return doubleMatrixMultiply(a, b, aDimensions[0], aDimensions[1], bDimensions[0], bDimensions[1], setDimNamesNode);
+                return doubleMatrixMultiply(a, b, aDimensions[0], aDimensions[1], bDimensions[0], bDimensions[1], setDimNamesNode, getADimNamesNode, getBDimNamesNode);
             } else {
                 int[] aDim = getADimsNode.getDimensions(a);
                 int aRows = aDim[0];
@@ -294,7 +296,7 @@ public abstract class MatMult extends RBuiltinNode {
                     bRows = 1;
                     bCols = b.getLength();
                 }
-                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, setDimNamesNode);
+                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
             }
         } else {
             if (bIsMatrix.profile(b.isMatrix())) {
@@ -310,7 +312,7 @@ public abstract class MatMult extends RBuiltinNode {
                     aRows = a.getLength();
                     aCols = 1;
                 }
-                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, setDimNamesNode);
+                return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
             } else {
                 if (a.getLength() != b.getLength()) {
                     errorProfile.enter();
@@ -643,8 +645,10 @@ public abstract class MatMult extends RBuiltinNode {
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return multiply(RClosures.createIntToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(RClosures.createIntToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     @Specialization
@@ -652,8 +656,10 @@ public abstract class MatMult extends RBuiltinNode {
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return multiply(a, RClosures.createIntToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(a, RClosures.createIntToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     @Specialization
@@ -661,8 +667,10 @@ public abstract class MatMult extends RBuiltinNode {
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return multiply(RClosures.createLogicalToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(RClosures.createLogicalToDoubleVector(a), b, aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     @Specialization
@@ -670,8 +678,10 @@ public abstract class MatMult extends RBuiltinNode {
                     @Cached("createBinaryProfile()") ConditionProfile aIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile bIsMatrix,
                     @Cached("createBinaryProfile()") ConditionProfile lengthEquals,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
-        return multiply(a, RClosures.createLogicalToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode);
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getADimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getBDimNamesNode) {
+        return multiply(a, RClosures.createLogicalToDoubleVector(b), aIsMatrix, bIsMatrix, lengthEquals, setDimNamesNode, getADimNamesNode, getBDimNamesNode);
     }
 
     // errors
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
index 16448cf18eef95829a39df2a9dded14bd48c3742..aad7cf177b7d81740c655ce56613f1e1c963262c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java
@@ -34,6 +34,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 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;
@@ -72,7 +73,8 @@ public abstract class NChar extends RBuiltinNode {
                     @Cached("create()") RAttributeProfiles attrProfiles,
                     @Cached("createBinaryProfile()") ConditionProfile nullDimNamesProfile,
                     @Cached("create()") GetDimAttributeNode getDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         int len = vector.getLength();
         int[] result = new int[len];
         loopProfile.profileCounted(len);
@@ -85,7 +87,7 @@ public abstract class NChar extends RBuiltinNode {
             }
         }
         RIntVector resultVector = RDataFactory.createIntVector(result, true, getDimNode.getDimensions(vector), vector.getNames(attrProfiles));
-        RList dimNames = vector.getDimNames(attrProfiles);
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (nullDimNamesProfile.profile(dimNames != null)) {
             setDimNamesNode.setDimNames(resultVector, dimNames);
         }
@@ -99,7 +101,8 @@ public abstract class NChar extends RBuiltinNode {
                     @Cached("create()") RAttributeProfiles attrProfiles,
                     @Cached("createBinaryProfile()") ConditionProfile nullDimNamesProfile,
                     @Cached("create()") GetDimAttributeNode getDimNode,
-                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode) {
+                    @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         int len = vector.getLength();
         int[] result = new int[len];
         loopProfile.profileCounted(len);
@@ -107,7 +110,7 @@ public abstract class NChar extends RBuiltinNode {
             result[i] = vector.getDataAt(i).length();
         }
         RIntVector resultVector = RDataFactory.createIntVector(result, true, getDimNode.getDimensions(vector), vector.getNames(attrProfiles));
-        RList dimNames = vector.getDimNames(attrProfiles);
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (nullDimNamesProfile.profile(dimNames != null)) {
             setDimNamesNode.setDimNames(resultVector, dimNames);
         }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
index 44cf8ad8d2579c37b58b8e58e41fb01f3511be54..2026a8ebc8f2a59ca9b2ddf63c48fc01ae431174 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
@@ -25,8 +25,9 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen;
-import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
@@ -50,7 +51,6 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 @RBuiltin(name = "t.default", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
 public abstract class Transpose extends RBuiltinNode {
 
-    private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     private final BranchProfile hasDimNamesProfile = BranchProfile.create();
     private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile();
 
@@ -61,6 +61,7 @@ public abstract class Transpose extends RBuiltinNode {
     @Child private InitAttributesNode initAttributes = InitAttributesNode.create();
     @Child private SetFixedAttributeNode putDimensions = SetFixedAttributeNode.createDim();
     @Child private SetFixedAttributeNode putDimNames = SetFixedAttributeNode.createDimNames();
+    @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
     public abstract Object execute(RAbstractVector o);
 
@@ -98,7 +99,7 @@ public abstract class Transpose extends RBuiltinNode {
         int[] newDim = new int[]{secondDim, firstDim};
         putDimensions.execute(initAttributes.execute(r), RDataFactory.createIntVector(newDim, RDataFactory.COMPLETE_VECTOR));
         // set new dim names
-        RList dimNames = vector.getDimNames(attrProfiles);
+        RList dimNames = getDimNamesNode.getDimNames(vector);
         if (dimNames != null) {
             hasDimNamesProfile.enter();
             assert dimNames.getLength() == 2;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
index 6983ebd12510e578c6d7934d4c476b231cbbf331..35adf33049ff8328091ce27e59d1947407474c8e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
@@ -51,7 +51,6 @@ public abstract class UpdateDimNames extends RBuiltinNode {
     protected static final String DIMNAMES_ATTR_KEY = RRuntime.DIMNAMES_ATTR_KEY;
 
     private final ConditionProfile shareListProfile = ConditionProfile.createBinaryProfile();
-    private final ConditionProfile isRVectorProfile = ConditionProfile.createBinaryProfile();
 
     @Child private CastStringNode castStringNode;
     @Child private CastToVectorNode castVectorNode;
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 a9b9c15b75f4df5c27f0cd00bf021c100f800b10..aad37e97d53a41b8ff4b242008b6410bed89fbbd 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
@@ -33,6 +33,7 @@ import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.access.vector.CachedExtractVectorNodeFactory.SetNamesNodeGen;
 import com.oracle.truffle.r.nodes.access.vector.PositionsCheckNode.PositionProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile;
@@ -283,14 +284,20 @@ final class CachedExtractVectorNode extends CachedVectorNode {
 
     @Child private SetDimAttributeNode setDimNode;
     @Child private SetDimNamesAttributeNode setDimNamesNode;
+    @Child private GetDimNamesAttributeNode getDimNamesNode;
 
     @ExplodeLoop
     private void applyDimensions(RAbstractContainer originalTarget, RVector<?> extractedTarget, int extractedTargetLength, PositionProfile[] positionProfile, Object[] positions) {
         // TODO speculate on the number of counted dimensions
         int dimCount = countDimensions(positionProfile);
 
+        if (getDimNamesNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getDimNamesNode = insert(GetDimNamesAttributeNode.create());
+        }
+
         int[] newDimensions = new int[dimCount];
-        RList originalDimNames = originalTarget.getDimNames(null);
+        RList originalDimNames = getDimNamesNode.getDimNames(originalTarget);
         RStringVector originalDimNamesNames;
         Object[] newDimNames;
         String[] newDimNamesNames;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java
index e437eef25787fc36433b988c3109a99dcd04ba6b..4b93498c0ddaca50eeb839023bb012c2e1b4ae8e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCharacterLookupNode.java
@@ -22,8 +22,10 @@
  */
 package com.oracle.truffle.r.nodes.access.vector;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
@@ -44,6 +46,7 @@ final class PositionCharacterLookupNode extends Node {
     private final BranchProfile emptyProfile = BranchProfile.create();
 
     @Child private SearchFirstStringNode searchNode;
+    @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
     PositionCharacterLookupNode(ElementAccessMode mode, int numDimensions, int dimensionIndex, boolean useNAForNotFound, boolean exact) {
         this.numDimensions = numDimensions;
@@ -63,7 +66,7 @@ final class PositionCharacterLookupNode extends Node {
             }
             result = searchNode.apply(names, position, notFoundStartIndex, position.materialize());
         } else {
-            RList dimNames = target.getDimNames(attributeProfiles);
+            RList dimNames = getDimNamesNode.getDimNames(target);
             if (dimNames != null) {
                 Object dataAt = dimNames.getDataAt(dimensionIndex);
                 if (dataAt != RNull.instance) {
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 ff585c63951527c39f63cf2a0b7b47c33c4a8017..04ba55c164fca27bfa664bf511459534beb1965c 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
@@ -29,6 +29,7 @@ import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
@@ -53,6 +54,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
     protected final RAttributeProfiles attrRightProfiles = RAttributeProfiles.create();
 
     @Child protected HasFixedAttributeNode hasDimNode = HasFixedAttributeNode.createDim();
+    @Child protected GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
     protected CopyAttributesNode(boolean copyAllAttributes) {
         this.copyAllAttributes = copyAllAttributes;
@@ -65,7 +67,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
     public abstract RAbstractVector execute(RAbstractVector target, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength);
 
     protected boolean containsMetadata(RAbstractVector vector, RAttributeProfiles attrProfiles) {
-        return vector instanceof RVector && hasDimNode.execute(vector) || (copyAllAttributes && vector.getAttributes() != null) || vector.getDimNames(attrProfiles) != null ||
+        return vector instanceof RVector && hasDimNode.execute(vector) || (copyAllAttributes && vector.getAttributes() != null) || getDimNamesNode.getDimNames(vector) != null ||
                         vector.getNames(attrProfiles) != null;
     }
 
@@ -183,7 +185,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
 
         if (result != left) {
-            RList newDimNames = left.getDimNames(attrLeftProfiles);
+            RList newDimNames = getDimNamesNode.getDimNames(left);
             if (hasDimNames.profile(newDimNames != null)) {
                 putDimNames.execute(result.getAttributes(), newDimNames);
 
@@ -191,7 +193,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
                 return result;
             }
             if (result != right) {
-                newDimNames = right.getDimNames(attrRightProfiles);
+                newDimNames = getDimNamesNode.getDimNames(right);
                 if (hasDimNames.profile(newDimNames != null)) {
                     setDimNamesNode.setDimNames(result, newDimNames);
                 }
@@ -250,7 +252,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
         RVector.verifyDimensions(result.getLength(), newDimensions, this);
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
         if (rightNotResult) {
-            RList newDimNames = right.getDimNames(attrRightProfiles);
+            RList newDimNames = getDimNamesNode.getDimNames(right);
             if (hasDimNames.profile(newDimNames != null)) {
                 setDimNamesNode.setDimNames(result, newDimNames);
             }
@@ -301,7 +303,7 @@ public abstract class CopyAttributesNode extends RBaseNode {
         }
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
         if (left != result) {
-            RList newDimNames = left.getDimNames(attrLeftProfiles);
+            RList newDimNames = getDimNamesNode.getDimNames(left);
             if (hasDimNames.profile(newDimNames != null)) {
                 setDimNamesNode.setDimNames(result, newDimNames);
             }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java
index 1a1f9a30a29ff7ee1df4990fa5326c50ddf0bf79..5421bc848c14eed477c711281ee65781d2e5b630 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UnaryCopyAttributesNode.java
@@ -28,6 +28,7 @@ import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -52,6 +53,7 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
     protected final RAttributeProfiles attrSourceProfiles = RAttributeProfiles.create();
 
     @Child protected HasFixedAttributeNode hasDimNode = HasFixedAttributeNode.createDim();
+    @Child protected GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
     protected UnaryCopyAttributesNode(boolean copyAllAttributes) {
         this.copyAllAttributes = copyAllAttributes;
@@ -65,7 +67,7 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
 
     protected boolean containsMetadata(RAbstractVector vector, RAttributeProfiles attrProfiles) {
         return vector instanceof RVector && hasDimNode.execute(vector) || (copyAllAttributes && vector.getAttributes() != null) || vector.getNames(attrProfiles) != null ||
-                        vector.getDimNames(attrProfiles) != null;
+                        getDimNamesNode.getDimNames(vector) != null;
     }
 
     @SuppressWarnings("unused")
@@ -92,7 +94,8 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
                     @Cached("createBinaryProfile()") ConditionProfile noDimensions, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNamesSource, //
                     @Cached("createBinaryProfile()") ConditionProfile hasDimNames,
-                    @Cached("create()") GetDimAttributeNode getDimsNode) {
+                    @Cached("create()") GetDimAttributeNode getDimsNode,
+                    @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) {
         RVector<?> result = target.materialize();
 
         if (copyAllAttributes) {
@@ -118,7 +121,7 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
 
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
 
-        RList newDimNames = source.getDimNames(attrSourceProfiles);
+        RList newDimNames = getDimNamesNode.getDimNames(source);
         if (hasDimNames.profile(newDimNames != null)) {
             putDimNames.execute(result.getAttributes(), newDimNames);
             newDimNames.elementNamePrefix = RRuntime.DIMNAMES_LIST_ELEMENT_NAME_PREFIX;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
index 569cc6483a43ba832a05a8fbf4b1e84eb69d6de7..98c7a907f719623928cc9cb233977b7fd2dce6f0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
@@ -32,6 +32,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.HasFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.primitive.UnaryMapNodeFactory.MapUnaryVectorInternalNodeGen;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
@@ -199,11 +200,12 @@ public final class UnaryMapNode extends RBaseNode {
     private final ConditionProfile hasNamesProfile = ConditionProfile.createBinaryProfile();
 
     @Child protected HasFixedAttributeNode hasDimNode = HasFixedAttributeNode.createDim();
+    @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create();
 
     private boolean containsMetadata(RAbstractVector vector) {
         return vector instanceof RVector &&
                         (hasDimensionsProfile.profile(hasDimNode.execute(vector)) || vector.getAttributes() != null || hasNamesProfile.profile(vector.getNames(attrProfiles) != null) ||
-                                        vector.getDimNames(attrProfiles) != null);
+                                        getDimNamesNode.getDimNames(vector) != null);
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
index 32b42ad68dcd797bd8f41902392963e6c28c7565..dc9c4d5ab6dda8de8a67359d734d4262bb19c724 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java
@@ -26,10 +26,11 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.runtime.NullProfile;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
@@ -51,6 +52,8 @@ public abstract class CastBaseNode extends CastNode {
     private final NullProfile hasNamesProfile = NullProfile.create();
     private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
     @Child private GetDimAttributeNode getDimNode;
+    @Child private SetDimNamesAttributeNode setDimNamesNode;
+    @Child private GetDimNamesAttributeNode getDimNamesNode;
 
     private final boolean preserveNames;
     private final boolean preserveDimensions;
@@ -60,13 +63,16 @@ public abstract class CastBaseNode extends CastNode {
         this.preserveNames = preserveNames;
         this.preserveDimensions = preserveDimensions;
         this.preserveAttributes = preserveAttributes;
+        if (preserveDimensions) {
+            getDimNamesNode = GetDimNamesAttributeNode.create();
+        }
     }
 
     public boolean preserveNames() {
         return preserveNames;
     }
 
-    public boolean preserveDimensions() {
+    public final boolean preserveDimensions() {
         return preserveDimensions;
     }
 
@@ -103,9 +109,13 @@ public abstract class CastBaseNode extends CastNode {
 
     protected void preserveDimensionNames(RAbstractContainer operand, RVector<?> ret) {
         if (preserveDimensions()) {
-            RList dimNames = operand.getDimNames(attrProfiles);
+            RList dimNames = getDimNamesNode.getDimNames(operand);
             if (hasDimNamesProfile.profile(dimNames != null)) {
-                ret.setDimNames((RList) dimNames.copy());
+                if (setDimNamesNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    setDimNamesNode = insert(SetDimNamesAttributeNode.create());
+                }
+                setDimNamesNode.setDimNames(ret, (RList) dimNames.copy());
             }
         }
     }