From 39c79a4da68822068ddd7eda33ee1dc8737491fc Mon Sep 17 00:00:00 2001
From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com>
Date: Fri, 2 Dec 2016 18:11:23 +0100
Subject: [PATCH] Replacing RAttributable.getAttr call sites by node
 invocations

---
 .../library/methods/MethodsListDispatch.java  |   8 +-
 .../oracle/truffle/r/library/stats/Cdist.java |   8 +-
 .../truffle/r/library/utils/TypeConvert.java  |   5 +-
 .../nodes/builtin/base/AsCharacterFactor.java |   6 +-
 .../truffle/r/nodes/builtin/base/Attr.java    |   1 -
 .../truffle/r/nodes/builtin/base/Combine.java |   1 -
 .../builtin/base/DatePOSIXFunctions.java      |   2 +-
 .../nodes/builtin/base/DynLoadFunctions.java  |   2 +-
 .../r/nodes/builtin/base/EnvFunctions.java    |  42 ++-
 .../r/nodes/builtin/base/FileFunctions.java   |   5 +-
 .../truffle/r/nodes/builtin/base/FormatC.java |   2 +-
 .../r/nodes/builtin/base/GrepFunctions.java   |  62 ++--
 .../builtin/base/HiddenInternalFunctions.java |   2 +-
 .../r/nodes/builtin/base/LaFunctions.java     |  12 +-
 .../truffle/r/nodes/builtin/base/Parse.java   |  14 +-
 .../r/nodes/builtin/base/ProcTime.java        |   2 +-
 .../r/nodes/builtin/base/ShortRowNames.java   |  10 +-
 .../r/nodes/builtin/base/Transpose.java       |   1 -
 .../r/nodes/builtin/base/UpdateAttr.java      |  20 +-
 .../nodes/builtin/base/UpdateAttributes.java  |  42 +--
 .../r/nodes/builtin/base/UpdateClass.java     |   4 +-
 .../r/nodes/builtin/base/UpdateDim.java       |   4 -
 .../r/nodes/builtin/base/UpdateLevels.java    |  11 +-
 .../r/nodes/builtin/base/UpdateOldClass.java  |   2 +-
 .../nodes/builtin/base/UpdateStorageMode.java |  11 +-
 .../r/nodes/builtin/base/infix/Tilde.java     |  14 +-
 .../base/printer/ExpressionPrinter.java       |   5 +-
 .../builtin/base/printer/ListPrinter.java     |  13 +-
 .../builtin/base/printer/PairListPrinter.java |   7 +-
 .../base/printer/ValuePrinterNode.java        |   2 +-
 .../builtin/base/printer/VectorPrinter.java   |  15 +-
 .../builtin/helpers/BrowserInteractNode.java  |  19 +-
 .../nodes/test/BinaryArithmeticNodeTest.java  |   1 -
 .../r/nodes/test/UnaryArithmeticNodeTest.java |   1 -
 .../vector/CachedExtractVectorNode.java       |   1 -
 .../nodes/attributes/CopyAttributesNode.java  |   4 -
 .../attributes/CopyOfRegAttributesNode.java   |   1 -
 .../r/nodes/attributes/GetAttributeNode.java  |  25 +-
 .../attributes/GetFixedAttributeNode.java     |  26 +-
 .../attributes/RemoveFixedAttributeNode.java  |   4 -
 .../r/nodes/attributes/SetAttributeNode.java  |  50 ++-
 .../attributes/SetClassAttributeNode.java     | 116 -------
 .../attributes/SetFixedAttributeNode.java     |  37 +-
 .../SpecialAttributesFunctions.java           | 318 ++++++++++++++++++
 .../attributes/UnaryCopyAttributesNode.java   |   2 -
 .../r/nodes/objects/GetS4DataSlot.java        |   4 +-
 .../truffle/r/nodes/objects/NewObject.java    |   3 +-
 .../truffle/r/nodes/unary/CastListNode.java   |  11 +-
 .../oracle/truffle/r/runtime/RChannel.java    |   1 -
 .../oracle/truffle/r/runtime/RSerialize.java  |   1 -
 .../truffle/r/runtime/conn/RConnection.java   |   1 -
 .../truffle/r/runtime/data/RAttributable.java |  10 +-
 .../r/runtime/data/RAttributesLayout.java     |   1 -
 .../truffle/r/runtime/data/RExpression.java   |   4 +-
 .../truffle/r/runtime/data/RLanguage.java     |   2 +-
 .../oracle/truffle/r/runtime/data/RList.java  |   4 +-
 .../truffle/r/runtime/data/RPairList.java     |   2 +-
 .../truffle/r/runtime/data/RVector.java       |  75 +++--
 58 files changed, 732 insertions(+), 327 deletions(-)
 delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetClassAttributeNode.java
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java

diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
index 882a6fcf1d..8aca802a24 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java
@@ -39,7 +39,6 @@ import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RExternalPtr;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -307,10 +306,11 @@ public class MethodsListDispatch {
 
         public abstract Object executeObject(String name, REnvironment rho, String pckg);
 
-        private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
         @Child private CastToVectorNode castToVector = CastToVectorNodeGen.create(false);
         @Child private ClassHierarchyScalarNode classHierarchyNode = ClassHierarchyScalarNodeGen.create();
         @Child private PromiseHelperNode promiseHelper;
+        @Child private GetFixedAttributeNode getGenericAttrNode = GetFixedAttributeNode.create(RRuntime.GENERIC_ATTR_KEY);
+        @Child private GetFixedAttributeNode getPckgAttrNode = GetFixedAttributeNode.create(RRuntime.PCKG_ATTR_KEY);
 
         @Specialization
         protected Object getGeneric(String name, REnvironment env, String pckg) {
@@ -327,9 +327,9 @@ public class MethodsListDispatch {
                 if (o != null) {
                     RAttributable vl = (RAttributable) o;
                     boolean ok = false;
-                    if (vl instanceof RFunction && vl.getAttr(attrProfiles, RRuntime.GENERIC_ATTR_KEY) != null) {
+                    if (vl instanceof RFunction && getGenericAttrNode.execute(vl) != null) {
                         if (pckg.length() > 0) {
-                            Object gpckgObj = vl.getAttr(attrProfiles, RRuntime.PCKG_ATTR_KEY);
+                            Object gpckgObj = getPckgAttrNode.execute(vl);
                             if (gpckgObj != null) {
                                 String gpckg = checkSingleString(castToVector.execute(gpckgObj), false, "The \"package\" slot in generic function object", this, classHierarchyNode);
                                 ok = pckg.equals(gpckg);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
index af6abfd1cd..1cfa2b74df 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
@@ -17,8 +17,9 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -33,6 +34,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck;
 public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
     private static final NACheck naCheck = NACheck.create();
 
+    @Child private GetFixedAttributeNode getNamesAttrNode = GetFixedAttributeNode.createNames();
+
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg(0).asDoubleVector();
@@ -54,7 +57,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         rdistance(xm.getDataWithoutCopying(), nr, nc, ans, false, methodObj, p);
         RDoubleVector result = RDataFactory.createDoubleVector(ans, naCheck.neverSeenNA());
         DynamicObject resultAttrs = result.initAttributes();
-        RStringVector names = (RStringVector) list.getAttr(RRuntime.NAMES_ATTR_KEY);
+
+        RStringVector names = (RStringVector) getNamesAttrNode.execute(list);
         for (int i = 0; i < names.getLength(); i++) {
             String name = names.getDataAt(i);
             Object listValue = list.getDataAt(i);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
index e856fd4783..49204b765d 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/TypeConvert.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
 import java.util.TreeSet;
 
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -37,6 +38,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
 
+    @Child private SetFixedAttributeNode setLevelsAttrNode = SetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
+
     private static boolean isNA(String s, RAbstractStringVector naStrings) {
         // naStrings are in addition to NA_character_
         if (RRuntime.isNA(s)) {
@@ -178,7 +181,7 @@ public abstract class TypeConvert extends RExternalBuiltinNode.Arg5 {
                 }
             }
             RIntVector res = RDataFactory.createIntVector(data, complete);
-            res.setAttr(RRuntime.LEVELS_ATTR_KEY, RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
+            setLevelsAttrNode.execute(res, RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR));
             return RVector.setVectorClassAttr(res, RDataFactory.createStringVector("factor"));
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
index 1db6100ba1..aa4fa4aae8 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacterFactor.java
@@ -25,8 +25,9 @@ package com.oracle.truffle.r.nodes.builtin.base;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
 import com.oracle.truffle.api.dsl.Specialization;
-
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
+
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.InheritsNode;
@@ -47,6 +48,7 @@ public abstract class AsCharacterFactor extends RBuiltinNode {
 
     @Child InheritsNode inheritsNode = InheritsNodeGen.create();
     @Child CastToVectorNode castToVectorNode = CastToVectorNode.create();
+    @Child private GetFixedAttributeNode getLevelsAttrNode = GetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
 
     @Specialization
     protected RStringVector doAsCharacterFactor(Object x) {
@@ -57,7 +59,7 @@ public abstract class AsCharacterFactor extends RBuiltinNode {
         RIntVector xVec = (RIntVector) x;
         int n = xVec.getLength();
         String[] data = new String[n];
-        Object levsAttr = xVec.getAttr(RRuntime.LEVELS_ATTR_KEY);
+        Object levsAttr = getLevelsAttrNode.execute(xVec);
         Object levs;
         if (levsAttr == null || !((levs = castToVectorNode.execute(levsAttr)) instanceof RAbstractStringVector)) {
             throw RError.error(RError.SHOW_CALLER, RError.Message.MALFORMED_FACTOR);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
index c9e2d6aaf5..6976f884cf 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java
@@ -36,7 +36,6 @@ import com.oracle.truffle.api.dsl.Specialization;
 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.ArrayAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.UpdateSharedAttributeNode;
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 431cc73c7d..e5e26a5b22 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,7 +47,6 @@ 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.SetFixedAttributeNode;
 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;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
index 9836382db9..16c0b8f946 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DatePOSIXFunctions.java
@@ -38,7 +38,7 @@ import java.util.TimeZone;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RInternalError;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
index b408232090..943bd6ee74 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
@@ -36,7 +36,7 @@ import java.util.ArrayList;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
index e5ae35b08c..d7188cf48b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java
@@ -49,6 +49,8 @@ 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.r.nodes.RRootNode;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.RList2EnvNode;
@@ -172,10 +174,14 @@ public class EnvFunctions {
             return list2Env.execute(list, env);
         }
 
+        protected GetFixedAttributeNode createGetXDataAttrNode() {
+            return GetFixedAttributeNode.create(RRuntime.DOT_XDATA);
+        }
+
         @Specialization
-        protected Object asEnvironment(RS4Object obj) {
+        protected Object asEnvironment(RS4Object obj, @Cached("createGetXDataAttrNode()") GetFixedAttributeNode getXDataAttrNode) {
             // generic dispatch tried already
-            Object xData = obj.getAttr(RRuntime.DOT_XDATA);
+            Object xData = getXDataAttrNode.execute(obj);
             if (xData == null || !(xData instanceof REnvironment)) {
                 throw RError.error(this, RError.Message.S4OBJECT_NX_ENVIRONMENT);
             } else {
@@ -319,8 +325,8 @@ public class EnvFunctions {
     @RBuiltin(name = "environment", kind = INTERNAL, parameterNames = {"fun"}, behavior = COMPLEX)
     public abstract static class Environment extends RBuiltinNode {
 
-        private static RAttributeProfiles attributeProfile = RAttributeProfiles.create();
         private final ConditionProfile attributable = ConditionProfile.createBinaryProfile();
+        @Child private GetFixedAttributeNode getEnvAttrNode;
 
         @Specialization
         protected Object environment(VirtualFrame frame, @SuppressWarnings("unused") RNull fun,
@@ -352,16 +358,24 @@ public class EnvFunctions {
         }
 
         @Specialization(guards = "isRFormula(formula)")
-        protected Object environment(RLanguage formula,
-                        @Cached("create()") RAttributeProfiles attrProfiles) {
-            Object result = formula.getAttr(attrProfiles, RRuntime.DOT_ENVIRONMENT);
+        protected Object environment(RLanguage formula) {
+            if (getEnvAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getEnvAttrNode = insert(GetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT));
+            }
+
+            Object result = getEnvAttrNode.execute(formula);
             return result == null ? RNull.instance : result;
         }
 
         @Specialization(guards = {"!isRNull(fun)", "!isRFunction(fun)", "!isRFormula(fun)"})
         protected Object environment(Object fun) {
             if (attributable.profile(fun instanceof RAttributable)) {
-                Object attr = ((RAttributable) fun).getAttr(attributeProfile, RRuntime.DOT_ENVIRONMENT);
+                if (getEnvAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    getEnvAttrNode = insert(GetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT));
+                }
+                Object attr = getEnvAttrNode.execute(fun);
                 return attr == null ? RNull.instance : attr;
             } else {
                 // Not an error according to GnuR
@@ -401,16 +415,22 @@ public class EnvFunctions {
             throw RError.error(this, RError.Message.USE_NULL_ENV_DEFUNCT);
         }
 
+        protected SetFixedAttributeNode createSetEnvAttrNode() {
+            return SetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT);
+        }
+
         @Specialization
         @TruffleBoundary
-        protected static Object updateEnvironment(RAbstractContainer obj, REnvironment env) {
-            return updateEnvironment((RAttributable) obj, env);
+        protected static Object updateEnvironment(RAbstractContainer obj, REnvironment env,
+                        @Cached("createSetEnvAttrNode()") SetFixedAttributeNode setEnvAttrNode) {
+            return updateEnvironment((RAttributable) obj, env, setEnvAttrNode);
         }
 
         @Specialization
         @TruffleBoundary
-        protected static Object updateEnvironment(RAttributable obj, REnvironment env) {
-            obj.setAttr(RRuntime.DOT_ENVIRONMENT, env);
+        protected static Object updateEnvironment(RAttributable obj, REnvironment env,
+                        @Cached("createSetEnvAttrNode()") SetFixedAttributeNode setEnvAttrNode) {
+            setEnvAttrNode.execute(obj, env);
             return obj;
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
index c9dbe8b0ba..63d8b68047 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
@@ -56,18 +56,17 @@ import java.util.stream.Stream;
 
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.Utils;
-import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.builtins.RBehavior;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.builtins.RBuiltinKind;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
index 04403d4fbf..c69f2dac6a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java
@@ -17,7 +17,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 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.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
index fbaf2c1d0e..a8b9153cca 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
@@ -11,7 +11,8 @@
  */
 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.notEmpty;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -26,6 +27,7 @@ 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.dsl.Specialization;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -664,6 +666,13 @@ public class GrepFunctions {
     @RBuiltin(name = "regexpr", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class Regexp extends CommonCodeAdapter {
 
+        @Child SetFixedAttributeNode setMatchLengthAttrNode = SetFixedAttributeNode.create("match.length");
+        @Child SetFixedAttributeNode setUseBytesAttrNode = SetFixedAttributeNode.create("useBytes");
+        @Child SetFixedAttributeNode setCaptureStartAttrNode = SetFixedAttributeNode.create("capture.start");
+        @Child SetFixedAttributeNode setCaptureLengthAttrNode = SetFixedAttributeNode.create("capture.length");
+        @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
+        @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
+
         @Override
         protected void createCasts(CastBuilder casts) {
             castPattern(casts);
@@ -755,19 +764,19 @@ public class GrepFunctions {
                 }
             }
             RIntVector ret = RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR);
-            ret.setAttr("match.length", RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
+            setMatchLengthAttrNode.execute(ret, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
             if (useBytes) {
-                ret.setAttr("useBytes", RRuntime.LOGICAL_TRUE);
+                setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE);
             }
             if (hasAnyCapture) {
                 RStringVector captureNamesVec = RDataFactory.createStringVector(captureNames, RDataFactory.COMPLETE_VECTOR);
                 RIntVector captureStartVec = RDataFactory.createIntVector(captureStart, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
-                captureStartVec.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
-                ret.setAttr("capture.start", captureStartVec);
+                setDimNamesAttrNode.execute(captureStartVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
+                setCaptureStartAttrNode.execute(ret, captureStartVec);
                 RIntVector captureLengthVec = RDataFactory.createIntVector(captureLength, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
-                captureLengthVec.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
-                ret.setAttr("capture.length", captureLengthVec);
-                ret.setAttr("capture.names", captureNamesVec);
+                setDimNamesAttrNode.execute(captureLengthVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
+                setCaptureLengthAttrNode.execute(ret, captureLengthVec);
+                setCaptureNamesAttrNode.execute(ret, captureNamesVec);
             }
             return ret;
         }
@@ -845,6 +854,13 @@ public class GrepFunctions {
     @RBuiltin(name = "gregexpr", kind = INTERNAL, parameterNames = {"pattern", "text", "ignore.case", "perl", "fixed", "useBytes"}, behavior = PURE)
     public abstract static class Gregexpr extends Regexp {
 
+        @Child SetFixedAttributeNode setMatchLengthAttrNode = SetFixedAttributeNode.create("match.length");
+        @Child SetFixedAttributeNode setUseBytesAttrNode = SetFixedAttributeNode.create("useBytes");
+        @Child SetFixedAttributeNode setCaptureStartAttrNode = SetFixedAttributeNode.create("capture.start");
+        @Child SetFixedAttributeNode setCaptureLengthAttrNode = SetFixedAttributeNode.create("capture.length");
+        @Child SetFixedAttributeNode setCaptureNamesAttrNode = SetFixedAttributeNode.create("capture.names");
+        @Child SetFixedAttributeNode setDimNamesAttrNode = SetFixedAttributeNode.createDimNames();
+
         @Override
         protected void createCasts(CastBuilder casts) {
             castPattern(casts);
@@ -855,19 +871,19 @@ public class GrepFunctions {
             castUseBytes(casts);
         }
 
-        private static void setNoCaptureAttributes(RIntVector vec, RStringVector captureNames) {
+        private void setNoCaptureAttributes(RIntVector vec, RStringVector captureNames) {
             int len = captureNames.getLength();
             int[] captureStartData = new int[len];
             int[] captureLengthData = new int[len];
             Arrays.fill(captureStartData, -1);
             Arrays.fill(captureLengthData, -1);
             RIntVector captureStart = RDataFactory.createIntVector(captureStartData, RDataFactory.COMPLETE_VECTOR, new int[]{1, captureNames.getLength()});
-            captureStart.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
+            setDimNamesAttrNode.execute(captureStart, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
             RIntVector captureLength = RDataFactory.createIntVector(captureLengthData, RDataFactory.COMPLETE_VECTOR, new int[]{1, captureNames.getLength()});
-            captureLength.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
-            vec.setAttr("capture.start", captureStart);
-            vec.setAttr("capture.length", captureLength);
-            vec.setAttr("capture.names", captureNames);
+            setDimNamesAttrNode.execute(captureLength, RDataFactory.createList(new Object[]{RNull.instance, captureNames.copy()}));
+            setCaptureStartAttrNode.execute(vec, captureStart);
+            setCaptureLengthAttrNode.execute(vec, captureLength);
+            setCaptureNamesAttrNode.execute(vec, captureNames);
         }
 
         @Specialization
@@ -899,16 +915,16 @@ public class GrepFunctions {
                     for (int j = 0; j < txt.length(); j++) {
                         res.setDataAt(res.getDataWithoutCopying(), j, j + 1);
                     }
-                    res.setAttr("match.length", RDataFactory.createIntVector(txt.length()));
+                    setMatchLengthAttrNode.execute(res, RDataFactory.createIntVector(txt.length()));
                     if (useBytes) {
-                        res.setAttr("useBytes", RRuntime.LOGICAL_TRUE);
+                        setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
                     }
                 } else {
                     List<Info> l = getInfo(pattern, vector.getDataAt(i), ignoreCase, perl, fixed);
                     res = toIndexOrSizeVector(l, true);
-                    res.setAttr("match.length", toIndexOrSizeVector(l, false));
+                    setMatchLengthAttrNode.execute(res, toIndexOrSizeVector(l, false));
                     if (useBytes) {
-                        res.setAttr("useBytes", RRuntime.LOGICAL_TRUE);
+                        setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
                     }
                     RIntVector captureStart = toCaptureStartOrLength(l, true);
                     if (captureStart != null) {
@@ -923,9 +939,9 @@ public class GrepFunctions {
                             }
                         }
                         hasAnyCapture = true;
-                        res.setAttr("capture.start", captureStart);
-                        res.setAttr("capture.length", captureLength);
-                        res.setAttr("capture.names", captureNames);
+                        setCaptureStartAttrNode.execute(res, captureStart);
+                        setCaptureLengthAttrNode.execute(res, captureLength);
+                        setCaptureNamesAttrNode.execute(res, captureNames);
                     } else if (hasAnyCapture) {
                         assert captureNames != null;
                         // it's capture names from previous iteration, so copy
@@ -947,7 +963,7 @@ public class GrepFunctions {
             return RDataFactory.createIntVector(arr, RDataFactory.COMPLETE_VECTOR);
         }
 
-        private static RIntVector toCaptureStartOrLength(List<Info> list, boolean start) {
+        private RIntVector toCaptureStartOrLength(List<Info> list, boolean start) {
             assert list.size() > 0;
             Info firstInfo = list.get(0);
             if (!firstInfo.hasCapture) {
@@ -966,7 +982,7 @@ public class GrepFunctions {
                 }
             }
             RIntVector ret = RDataFactory.createIntVector(arr, RDataFactory.COMPLETE_VECTOR, new int[]{list.size(), firstInfo.captureNames.length});
-            ret.setAttr(RRuntime.DIMNAMES_ATTR_KEY, RDataFactory.createList(new Object[]{RNull.instance, RDataFactory.createStringVector(firstInfo.captureNames, RDataFactory.COMPLETE_VECTOR)}));
+            setDimNamesAttrNode.execute(ret, RDataFactory.createList(new Object[]{RNull.instance, RDataFactory.createStringVector(firstInfo.captureNames, RDataFactory.COMPLETE_VECTOR)}));
             return ret;
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
index 2bffe1729c..d04b57fd08 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java
@@ -36,7 +36,7 @@ import com.oracle.truffle.api.nodes.LoopNode;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.ConstantNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
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 2dad6301ea..45b9ae431e 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
@@ -31,6 +31,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 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.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
@@ -368,6 +369,8 @@ public class LaFunctions {
         private final ConditionProfile doUseLog = ConditionProfile.createBinaryProfile();
         private final NACheck naCheck = NACheck.create();
 
+        @Child private SetFixedAttributeNode setLogAttrNode = SetFixedAttributeNode.create("logarithm");
+
         @Override
         protected void createCasts(CastBuilder casts) {
             //@formatter:off
@@ -437,7 +440,7 @@ public class LaFunctions {
                 }
             }
             RDoubleVector modulusVec = RDataFactory.createDoubleVectorFromScalar(modulus);
-            modulusVec.setAttr("logarithm", RRuntime.asLogical(useLog));
+            setLogAttrNode.execute(modulusVec, RRuntime.asLogical(useLog));
             RList result = RDataFactory.createList(new Object[]{modulusVec, sign}, NAMES_VECTOR);
             RVector.setVectorClassAttr(result, DET_CLASS);
             return result;
@@ -450,6 +453,9 @@ public class LaFunctions {
         private final BranchProfile errorProfile = BranchProfile.create();
         private final ConditionProfile noPivot = ConditionProfile.createBinaryProfile();
 
+        @Child private SetFixedAttributeNode setPivotAttrNode = SetFixedAttributeNode.create("pivot");
+        @Child private SetFixedAttributeNode setRankAttrNode = SetFixedAttributeNode.create("rank");
+
         @Override
         protected void createCasts(CastBuilder casts) {
             //@formatter:off
@@ -499,8 +505,8 @@ public class LaFunctions {
                     // TODO informative error message (aka GnuR)
                     throw RError.error(this, RError.Message.LAPACK_ERROR, info, "dpotrf");
                 }
-                a.setAttr("pivot", RRuntime.asLogical(piv));
-                a.setAttr("rank", rank[0]);
+                setPivotAttrNode.execute(a, RRuntime.asLogical(piv));
+                setRankAttrNode.execute(a, rank[0]);
                 RList dn = a.getDimNames();
                 if (dn != null && dn.getDataAt(0) != null) {
                     Object[] dn2 = new Object[m];
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
index 8ac93354d9..34cbb98adf 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java
@@ -33,8 +33,10 @@ import java.net.URISyntaxException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -96,6 +98,10 @@ public abstract class Parse extends RBuiltinNode {
     @Child private CastStringNode castStringNode;
     @Child private CastToVectorNode castVectorNode;
 
+    @Child private SetFixedAttributeNode setSrcRefAttrNode = SetFixedAttributeNode.create("srcref");
+    @Child private SetFixedAttributeNode setWholeSrcRefAttrNode = SetFixedAttributeNode.create("wholeSrcref");
+    @Child private SetFixedAttributeNode setSrcFileAttrNode = SetFixedAttributeNode.create("srcfile");
+
     @Override
     protected void createCasts(CastBuilder casts) {
         // Note: string is captured by the R wrapper and transformed to a file, other types not
@@ -219,7 +225,7 @@ public abstract class Parse extends RBuiltinNode {
         }
     }
 
-    private static void addAttributes(RExpression exprs, Source source, REnvironment srcFile) {
+    private void addAttributes(RExpression exprs, Source source, REnvironment srcFile) {
         Object[] srcrefData = new Object[exprs.getLength()];
         for (int i = 0; i < srcrefData.length; i++) {
             Object data = exprs.getDataAt(i);
@@ -239,7 +245,7 @@ public abstract class Parse extends RBuiltinNode {
             }
 
         }
-        exprs.setAttr("srcref", RDataFactory.createList(srcrefData));
+        setSrcRefAttrNode.execute(exprs, RDataFactory.createList(srcrefData));
         int[] wholeSrcrefData = new int[8];
         int endOffset = source.getCode().length() - 1;
         wholeSrcrefData[0] = source.getLineNumber(0);
@@ -248,8 +254,8 @@ public abstract class Parse extends RBuiltinNode {
         wholeSrcrefData[6] = wholeSrcrefData[0];
         wholeSrcrefData[6] = wholeSrcrefData[3];
 
-        exprs.setAttr("wholeSrcref", RDataFactory.createIntVector(wholeSrcrefData, RDataFactory.COMPLETE_VECTOR));
-        exprs.setAttr("srcfile", srcFile);
+        setWholeSrcRefAttrNode.execute(exprs, RDataFactory.createIntVector(wholeSrcrefData, RDataFactory.COMPLETE_VECTOR));
+        setSrcFileAttrNode.execute(exprs, srcFile);
     }
 
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
index ea86a45e96..24496e3ae2 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ProcTime.java
@@ -27,7 +27,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
index e318c352f9..0676f6ba7a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ShortRowNames.java
@@ -27,10 +27,12 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lte;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.IntValueProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -50,6 +52,8 @@ public abstract class ShortRowNames extends RBuiltinNode {
     private final BranchProfile errorProfile = BranchProfile.create();
     private final ValueProfile operandTypeProfile = ValueProfile.createClassProfile();
 
+    @Child private GetFixedAttributeNode getRowNamesAttrNode;
+
     @Override
     protected void createCasts(CastBuilder casts) {
         casts.arg("type").asIntegerVector().findFirst().mustBe(gte0().and(lte(2)));
@@ -64,7 +68,11 @@ public abstract class ShortRowNames extends RBuiltinNode {
         if (operand instanceof RAbstractContainer) {
             rowNames = ((RAbstractContainer) operand).getRowNames(attrProfiles);
         } else if (operand instanceof REnvironment) {
-            rowNames = ((REnvironment) operand).getAttr(attrProfiles, RRuntime.ROWNAMES_ATTR_KEY);
+            if (getRowNamesAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getRowNamesAttrNode = insert(GetFixedAttributeNode.create(RRuntime.ROWNAMES_ATTR_KEY));
+            }
+            rowNames = getRowNamesAttrNode.execute(operand);
         } else {
             // for any other type GnuR returns 0
             return 0;
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 ec945bb76c..2d936337b0 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
@@ -96,7 +96,6 @@ public abstract class Transpose extends RBuiltinNode {
         copyRegAttributes.execute(vector, r);
         // set new dimensions
         int[] newDim = new int[]{secondDim, firstDim};
-        r.setInternalDimensions(newDim);
         putDimensions.execute(initAttributes.execute(r), RDataFactory.createIntVector(newDim, RDataFactory.COMPLETE_VECTOR));
         // set new dim names
         RList dimNames = vector.getDimNames(attrProfiles);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
index a710425530..f1fcfd5dc4 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttr.java
@@ -31,12 +31,12 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 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.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetRowNamesAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -70,6 +70,8 @@ public abstract class UpdateAttr extends RBuiltinNode {
     @Child private CastToVectorNode castVector;
     @Child private CastListNode castList;
     @Child private SetClassAttributeNode setClassAttrNode;
+    @Child private SetRowNamesAttributeNode setRowNamesAttrNode;
+    @Child private SetAttributeNode setGenAttrNode;
 
     @CompilationFinal private String cachedName = "";
     @CompilationFinal private String cachedInternedName = "";
@@ -197,10 +199,18 @@ public abstract class UpdateAttr extends RBuiltinNode {
             setClassAttrNode.execute(result, convertClassAttrFromObject(value));
             return result;
         } else if (internedName == RRuntime.ROWNAMES_ATTR_KEY) {
-            result.setRowNames(castVector(value));
+            if (setRowNamesAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setRowNamesAttrNode = insert(SetRowNamesAttributeNode.create());
+            }
+            setRowNamesAttrNode.execute(result, castVector(value));
         } else {
             // generic attribute
-            result.setAttr(internedName, value);
+            if (setGenAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setGenAttrNode = insert(SetAttributeNode.create());
+            }
+            setGenAttrNode.execute(result, internedName, value);
         }
 
         return result;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
index de564de896..744664502b 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java
@@ -30,11 +30,10 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastIntegerNode;
@@ -64,8 +63,6 @@ public abstract class UpdateAttributes extends RBuiltinNode {
     @Child private UpdateDimNames updateDimNames;
     @Child private CastIntegerNode castInteger;
     @Child private CastToVectorNode castVector;
-    @Child private SetClassAttributeNode setClassAttrNode;
-    @Child private InitAttributesNode initAttrNode;
     @Child private SetAttributeNode setAttrNode;
 
     @Override
@@ -196,14 +193,10 @@ public abstract class UpdateAttributes extends RBuiltinNode {
             } else if (attrName.equals(RRuntime.DIMNAMES_ATTR_KEY)) {
                 res = updateDimNames(res, value);
             } else if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) {
-                if (setClassAttrNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    setClassAttrNode = insert(SetClassAttributeNode.create());
-                }
                 if (value == RNull.instance) {
-                    setClassAttrNode.reset(result);
+                    res.setClassAttr(null);
                 } else {
-                    setClassAttrNode.execute(res, UpdateAttr.convertClassAttrFromObject(value));
+                    res.setClassAttr(UpdateAttr.convertClassAttrFromObject(value));
                 }
                 res = result;
             } else if (attrName.equals(RRuntime.ROWNAMES_ATTR_KEY)) {
@@ -212,7 +205,11 @@ public abstract class UpdateAttributes extends RBuiltinNode {
                 if (value == RNull.instance) {
                     res.removeAttr(attrProfiles, attrName);
                 } else {
-                    res.setAttr(attrName.intern(), value);
+                    if (setAttrNode == null) {
+                        CompilerDirectives.transferToInterpreterAndInvalidate();
+                        setAttrNode = insert(SetAttributeNode.create());
+                    }
+                    setAttrNode.execute(res, attrName.intern(), value);
                 }
             }
         }
@@ -234,12 +231,7 @@ public abstract class UpdateAttributes extends RBuiltinNode {
         Object obj = getNonShared(o);
         RAttributable attrObj = (RAttributable) obj;
         attrObj.removeAllAttributes();
-
-        if (setClassAttrNode == null) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-            setClassAttrNode = insert(SetClassAttributeNode.create());
-        }
-        setClassAttrNode.reset(attrObj);
+        attrObj.setClassAttr(null);
         return obj;
     }
 
@@ -269,21 +261,9 @@ public abstract class UpdateAttributes extends RBuiltinNode {
                     throw RError.error(this, RError.Message.SET_INVALID_CLASS_ATTR);
                 }
 
-                if (setClassAttrNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    setClassAttrNode = insert(SetClassAttributeNode.create());
-                }
-                setClassAttrNode.execute(attrObj, UpdateAttr.convertClassAttrFromObject(attrValue));
+                attrObj.setClassAttr(UpdateAttr.convertClassAttrFromObject(attrValue));
             } else {
-                if (setAttrNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    setAttrNode = insert(SetAttributeNode.create());
-                }
-                if (initAttrNode == null) {
-                    CompilerDirectives.transferToInterpreterAndInvalidate();
-                    initAttrNode = insert(InitAttributesNode.create());
-                }
-                setAttrNode.execute(initAttrNode.execute(attrObj), attrName.intern(), operand.getDataAt(i));
+                attrObj.setAttr(attrName.intern(), operand.getDataAt(i));
             }
         }
         return obj;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
index 674c82de16..e2e71f8036 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java
@@ -18,9 +18,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node.Child;
-import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
 import com.oracle.truffle.r.nodes.binary.CastTypeNodeGen;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
index 0b7c49004d..3195770285 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDim.java
@@ -31,14 +31,11 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -72,7 +69,6 @@ public abstract class UpdateDim extends RBuiltinNode {
         int[] dimsData = dimensionsMaterialized.getDataCopy();
         RVector.verifyDimensions(vector.getLength(), dimsData, this);
         RVector<?> result = ((RAbstractVector) reuse.execute(vector)).materialize();
-        result.setInternalDimensions(dimsData);
         result.setInternalNames(null);
         result.setInternalDimNames(null);
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
index b9f41698d5..329730c362 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateLevels.java
@@ -15,7 +15,9 @@ 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.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -44,10 +46,15 @@ public abstract class UpdateLevels extends RBuiltinNode {
         return v;
     }
 
+    protected SetFixedAttributeNode createSetLevelsAttrNode() {
+        return SetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
+    }
+
     @Specialization(guards = "!isRNull(levels)")
-    protected RAbstractVector updateLevels(RAbstractVector vector, Object levels) {
+    protected RAbstractVector updateLevels(RAbstractVector vector, Object levels,
+                    @Cached("createSetLevelsAttrNode()") SetFixedAttributeNode setLevelsAttrNode) {
         RVector<?> v = (RVector<?>) vector.getNonShared();
-        v.setAttr(RRuntime.LEVELS_ATTR_KEY, levels);
+        setLevelsAttrNode.execute(v, levels);
         return v;
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
index 375dc81129..02c1ab3e72 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
@@ -29,7 +29,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
index 2828a0bcc5..804b73b667 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java
@@ -20,7 +20,8 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNode;
 import com.oracle.truffle.r.nodes.attributes.TypeFromModeNodeGen;
 import com.oracle.truffle.r.nodes.binary.CastTypeNode;
@@ -36,9 +37,7 @@ import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 
 @RBuiltin(name = "storage.mode<-", kind = PRIMITIVE, parameterNames = {"x", "value"}, behavior = PURE)
@@ -53,7 +52,9 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
     private final BranchProfile errorProfile = BranchProfile.create();
 
     @Specialization
-    protected Object update(Object x, String value, @Cached("create()") ArrayAttributeNode attrAttrAccess) {
+    protected Object update(Object x, String value,
+                    @Cached("create()") ArrayAttributeNode attrAttrAccess,
+                    @Cached("create()") SetAttributeNode setAttrNode) {
         RType mode = typeFromMode.execute(value);
         if (mode == RType.DefunctReal || mode == RType.DefunctSingle) {
             errorProfile.enter();
@@ -94,7 +95,7 @@ public abstract class UpdateStorageMode extends RBuiltinNode {
                                     setClassAttrNode.execute(rresult, v);
                                 }
                             } else {
-                                rresult.setAttr(Utils.intern(attrName), v);
+                                setAttrNode.execute(rresult, Utils.intern(attrName), v);
                             }
                         }
                         return rresult;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
index 00771501a3..1918c7c744 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Tilde.java
@@ -25,10 +25,11 @@ package com.oracle.truffle.r.nodes.builtin.base.infix;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_FRAME;
 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.frame.VirtualFrame;
-import com.oracle.truffle.api.nodes.Node.Child;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.function.RCallNode;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -58,13 +59,18 @@ public abstract class Tilde extends RBuiltinNode {
         return new Object[]{RMissing.instance, RMissing.instance};
     }
 
+    protected SetFixedAttributeNode createSetEnvAttrNode() {
+        return SetFixedAttributeNode.create(RRuntime.DOT_ENVIRONMENT);
+    }
+
     @Specialization
-    protected RLanguage tilde(VirtualFrame frame, @SuppressWarnings("unused") Object response, @SuppressWarnings("unused") Object model) {
+    protected RLanguage tilde(VirtualFrame frame, @SuppressWarnings("unused") Object response, @SuppressWarnings("unused") Object model,
+                    @Cached("createSetEnvAttrNode()") SetFixedAttributeNode setEnvAttrNode) {
         RCallNode call = (RCallNode) ((RBaseNode) getParent()).asRSyntaxNode();
         RLanguage lang = RDataFactory.createLanguage(call);
         setClassAttrNode.execute(lang, FORMULA_CLASS);
         REnvironment env = REnvironment.frameToEnvironment(frame.materialize());
-        lang.setAttr(RRuntime.DOT_ENVIRONMENT, env);
+        setEnvAttrNode.execute(lang, env);
         return lang;
     }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java
index d8fcdd5d29..5e15b1beaf 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ExpressionPrinter.java
@@ -27,7 +27,6 @@ import java.io.PrintWriter;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RExpression;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
@@ -39,8 +38,6 @@ final class ExpressionPrinter extends AbstractValuePrinter<RExpression> {
         // singleton
     }
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     @Override
     @TruffleBoundary
     protected void printValue(RExpression expr, PrintContext printCtx) throws IOException {
@@ -49,7 +46,7 @@ final class ExpressionPrinter extends AbstractValuePrinter<RExpression> {
         valPrintCtx.parameters().setSuppressIndexLabels(true);
 
         out.print("expression(");
-        RStringVector names = (RStringVector) expr.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY);
+        RStringVector names = (RStringVector) expr.getAttr(RRuntime.NAMES_ATTR_KEY);
         for (int i = 0; i < expr.getLength(); i++) {
             if (i != 0) {
                 out.print(", ");
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
index ffc0c1db1b..cf6378f2f6 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
@@ -24,7 +24,6 @@ import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLanguage;
@@ -49,15 +48,13 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
         // singleton
     }
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     private static int TAGBUFLEN = 256;
 
     @Override
     @TruffleBoundary
     protected void printValue(RAbstractListVector s, PrintContext printCtx) throws IOException {
         RAbstractIntVector dims = Utils.<RAbstractIntVector> castTo(
-                        s.getAttr(dummyAttrProfiles, RRuntime.DIM_ATTR_KEY));
+                        s.getAttr(RRuntime.DIM_ATTR_KEY));
 
         if (dims != null && dims.getLength() > 1) {
             printDimList(s, printCtx);
@@ -151,7 +148,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
         }
 
         RStringVector tt = RDataFactory.createStringVector(t, true, s.getDimensions());
-        Object dimNames = s.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY);
+        Object dimNames = s.getAttr(RRuntime.DIMNAMES_ATTR_KEY);
         tt.setAttr(RRuntime.DIMNAMES_ATTR_KEY, dimNames);
 
         PrintContext cc = printCtx.cloneContext();
@@ -171,7 +168,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
         int ns = s.getLength();
 
         RAbstractStringVector names;
-        names = Utils.castTo(RRuntime.asAbstractVector(s.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY)));
+        names = Utils.castTo(RRuntime.asAbstractVector(s.getAttr(RRuntime.NAMES_ATTR_KEY)));
 
         if (ns > 0) {
             int npr = (ns <= pp.getMax() + 1) ? ns : pp.getMax();
@@ -216,7 +213,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
 
                 out.println(tagbuf);
                 Object si = s.getDataAtAsObject(i);
-                if (si instanceof RAttributable && ((RAttributable) si).isObject(dummyAttrProfiles)) {
+                if (si instanceof RAttributable && ((RAttributable) si).isObject()) {
                     RContext.getEngine().printResult(si);
                 } else {
                     ValuePrinters.INSTANCE.print(si, printCtx);
@@ -236,7 +233,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
             /* Formal classes are represented as empty lists */
             String className = null;
             if (printCtx.printerNode().isObject(s) && printCtx.printerNode().isMethodDispatchOn()) {
-                RAbstractStringVector klass = Utils.castTo(RRuntime.asAbstractVector(s.getAttr(dummyAttrProfiles, RRuntime.CLASS_ATTR_KEY)));
+                RAbstractStringVector klass = Utils.castTo(RRuntime.asAbstractVector(s.getAttr(RRuntime.CLASS_ATTR_KEY)));
                 if (klass != null && klass.getLength() == 1) {
                     String ss = klass.getDataAt(0);
                     String str = snprintf(200, ".__C__%s", ss);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
index 9dabad114d..5927ddf98e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PairListPrinter.java
@@ -17,7 +17,6 @@ import java.io.IOException;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -42,13 +41,11 @@ final class PairListPrinter extends AbstractValuePrinter<RPairList> {
         // singleton
     }
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     @Override
     @TruffleBoundary
     protected void printValue(RPairList s, PrintContext printCtx) throws IOException {
         final RAbstractIntVector dims = Utils.<RAbstractIntVector> castTo(
-                        s.getAttr(dummyAttrProfiles, RRuntime.DIM_ATTR_KEY));
+                        s.getAttr(RRuntime.DIM_ATTR_KEY));
 
         final int ns = s.getLength();
 
@@ -82,7 +79,7 @@ final class PairListPrinter extends AbstractValuePrinter<RPairList> {
                 t[i] = pbuf;
 
                 RStringVector tt = RDataFactory.createStringVector(t, true, s.getDimensions());
-                Object dimNames = s.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY);
+                Object dimNames = s.getAttr(RRuntime.DIMNAMES_ATTR_KEY);
                 tt.setAttr(RRuntime.DIMNAMES_ATTR_KEY, dimNames);
 
                 PrintContext cc = printCtx.cloneContext();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
index cbcb5e2af9..7448ebc751 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java
@@ -542,7 +542,7 @@ public final class ValuePrinterNode extends RBaseNode {
         }
 
         @Override
-        public void setNames(RStringVector newNames) {
+        public final void setNames(RStringVector newNames) {
             throw RInternalError.shouldNotReachHere();
         }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
index dcbc682204..3167f0062c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java
@@ -19,7 +19,6 @@ import java.io.PrintWriter;
 
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -29,8 +28,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePrinter<T> {
 
-    private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create();
-
     @Override
     protected void printValue(T vector, PrintContext printCtx) throws IOException {
         printVector(vector, 1, printCtx);
@@ -77,13 +74,13 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
 
             MatrixDimNames mdn = null;
 
-            Object dimAttr = vector.getAttr(dummyAttrProfiles, RRuntime.DIM_ATTR_KEY);
+            Object dimAttr = vector.getAttr(RRuntime.DIM_ATTR_KEY);
             if (dimAttr instanceof RAbstractIntVector) {
                 dims = (RAbstractIntVector) dimAttr;
                 if (dims.getLength() == 1) {
-                    RList t = Utils.<RList> castTo(vector.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY));
+                    RList t = Utils.<RList> castTo(vector.getAttr(RRuntime.DIMNAMES_ATTR_KEY));
                     if (t != null && t.getDataAt(0) != null) {
-                        RAbstractStringVector nn = Utils.castTo(RRuntime.asAbstractVector(t.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY)));
+                        RAbstractStringVector nn = Utils.castTo(RRuntime.asAbstractVector(t.getAttr(RRuntime.NAMES_ATTR_KEY)));
 
                         if (nn != null) {
                             title = nn.getDataAt(0);
@@ -111,7 +108,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
                 }
             } else {
                 dims = null;
-                Object namesAttr = Utils.castTo(vector.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY));
+                Object namesAttr = Utils.castTo(vector.getAttr(RRuntime.NAMES_ATTR_KEY));
                 if (namesAttr != null) {
                     if (vector.getLength() > 0) {
                         names = Utils.castTo(RRuntime.asAbstractVector(namesAttr));
@@ -676,7 +673,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
         final RAbstractStringVector axisNames;
 
         MatrixDimNames(RAbstractVector x) {
-            dimnames = Utils.<RList> castTo(x.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY));
+            dimnames = Utils.<RList> castTo(x.getAttr(RRuntime.DIMNAMES_ATTR_KEY));
 
             if (dimnames == null) {
                 rl = null;
@@ -688,7 +685,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri
             } else {
                 rl = getDimNamesAt(0);
                 cl = getDimNamesAt(1);
-                axisNames = Utils.<RAbstractStringVector> castTo(dimnames.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY));
+                axisNames = Utils.<RAbstractStringVector> castTo(dimnames.getAttr(RRuntime.NAMES_ATTR_KEY));
                 if (axisNames == null) {
                     rn = null;
                     cn = null;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
index 044773513f..78c4fd4820 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
@@ -27,6 +27,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.runtime.JumpToTopLevelException;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -69,6 +70,9 @@ public abstract class BrowserInteractNode extends RNode {
     public static final int CONTINUE = 2;
     public static final int FINISH = 3;
 
+    @Child private GetFixedAttributeNode getSrcRefAttrNode;
+    @Child private GetFixedAttributeNode getSrcFileAttrNode;
+
     @Specialization
     protected int interact(VirtualFrame frame) {
         CompilerDirectives.transferToInterpreter();
@@ -179,11 +183,20 @@ public abstract class BrowserInteractNode extends RNode {
         return RCaller.create(null, currentCaller, builder.call(RSyntaxNode.INTERNAL, builder.lookup(RSyntaxNode.INTERNAL, "browser", true)));
     }
 
-    private static String getSrcinfo(RStringVector element) {
-        Object srcref = element.getAttr(RRuntime.R_SRCREF);
+    private String getSrcinfo(RStringVector element) {
+        if (getSrcRefAttrNode == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getSrcRefAttrNode = insert(GetFixedAttributeNode.create(RRuntime.R_SRCREF));
+        }
+
+        Object srcref = getSrcRefAttrNode.execute(element);
         if (srcref != null) {
+            if (getSrcFileAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                getSrcFileAttrNode = insert(GetFixedAttributeNode.create(RRuntime.R_SRCFILE));
+            }
             RIntVector lloc = (RIntVector) srcref;
-            Object srcfile = lloc.getAttr(RRuntime.R_SRCFILE);
+            Object srcfile = getSrcFileAttrNode.execute(lloc);
             if (srcfile != null) {
                 REnvironment env = (REnvironment) srcfile;
                 return " at " + RRuntime.asString(env.get(RSrcref.SrcrefFields.filename.name())) + "#" + lloc.getDataAt(0);
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
index 668afbfc22..ce538982b0 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/BinaryArithmeticNodeTest.java
@@ -67,7 +67,6 @@ import com.oracle.truffle.r.nodes.binary.BinaryArithmeticNode;
 import com.oracle.truffle.r.nodes.test.TestUtilities.NodeHandle;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java
index d231d36810..5a7ef2b6e1 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/UnaryArithmeticNodeTest.java
@@ -56,7 +56,6 @@ import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNode;
 import com.oracle.truffle.r.nodes.unary.UnaryArithmeticNodeGen;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
 import com.oracle.truffle.r.runtime.data.RSequence;
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 9013ee9717..b81069298c 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,7 +33,6 @@ 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.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
 import com.oracle.truffle.r.runtime.RError;
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 e1f30141ef..31b4442825 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
@@ -150,7 +150,6 @@ public abstract class CopyAttributesNode extends RBaseNode {
                     removeDimNames.execute(attributes);
                     result.setInternalDimNames(null);
                 }
-                result.setInternalDimensions(null);
 
                 RStringVector vecNames = left.getNames(attrLeftProfiles);
                 if (hasNamesLeft.profile(vecNames != null)) {
@@ -176,7 +175,6 @@ public abstract class CopyAttributesNode extends RBaseNode {
         }
 
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
 
         if (result != left) {
             RList newDimNames = left.getDimNames(attrLeftProfiles);
@@ -243,7 +241,6 @@ public abstract class CopyAttributesNode extends RBaseNode {
 
         RVector.verifyDimensions(result.getLength(), newDimensions, this);
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
         if (rightNotResult) {
             RList newDimNames = right.getDimNames(attrRightProfiles);
             if (hasDimNames.profile(newDimNames != null)) {
@@ -292,7 +289,6 @@ public abstract class CopyAttributesNode extends RBaseNode {
             leftHasDimensions.enter();
         }
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
         if (left != result) {
             RList newDimNames = left.getDimNames(attrLeftProfiles);
             if (hasDimNames.profile(newDimNames != 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 7b6897b18b..af0a87e247 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
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
-import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.Property;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java
index 0a28d002af..a3d0c24731 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributeNode.java
@@ -22,16 +22,20 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
-import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.runtime.data.RAttributable;
 
 public abstract class GetAttributeNode extends AttributeAccessNode {
 
+    @Child private GetAttributeNode recursive;
+
     protected GetAttributeNode() {
     }
 
@@ -39,7 +43,7 @@ public abstract class GetAttributeNode extends AttributeAccessNode {
         return GetAttributeNodeGen.create();
     }
 
-    public abstract Object execute(DynamicObject attrs, String name);
+    public abstract Object execute(Object attrs, String name);
 
     @Specialization(limit = "3", //
                     guards = {"cachedName.equals(name)", "shapeCheck(shape, attrs)"}, //
@@ -58,4 +62,21 @@ public abstract class GetAttributeNode extends AttributeAccessNode {
         return attrs.get(name);
     }
 
+    @Specialization
+    protected Object getAttrFromAttributable(RAttributable x, String name,
+                    @Cached("create()") BranchProfile attrNullProfile) {
+        DynamicObject attributes = x.getAttributes();
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return null;
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create());
+        }
+
+        return recursive.execute(attributes, name);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
index 35b79c0d78..00044e606d 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
@@ -22,17 +22,21 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
-import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributable;
 
 public abstract class GetFixedAttributeNode extends FixedAttributeAccessNode {
 
+    @Child private GetFixedAttributeNode recursive;
+
     protected GetFixedAttributeNode(String name) {
         super(name);
     }
@@ -53,7 +57,7 @@ public abstract class GetFixedAttributeNode extends FixedAttributeAccessNode {
         return GetFixedAttributeNode.create(RRuntime.CLASS_ATTR_KEY);
     }
 
-    public abstract Object execute(DynamicObject attrs);
+    public abstract Object execute(Object attrs);
 
     protected boolean hasProperty(Shape shape) {
         return shape.hasProperty(name);
@@ -74,4 +78,22 @@ public abstract class GetFixedAttributeNode extends FixedAttributeAccessNode {
     protected Object getAttrFallback(DynamicObject attrs) {
         return attrs.get(name);
     }
+
+    @Specialization
+    protected Object getAttrFromAttributable(RAttributable x,
+                    @Cached("create()") BranchProfile attrNullProfile) {
+        DynamicObject attributes = x.getAttributes();
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return null;
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create(name));
+        }
+
+        return recursive.execute(attributes);
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java
index bb698a4a45..1b7ed881a0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveFixedAttributeNode.java
@@ -23,12 +23,8 @@
 package com.oracle.truffle.r.nodes.attributes;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.object.DynamicObject;
-import com.oracle.truffle.api.object.Property;
-import com.oracle.truffle.api.object.Shape;
-import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 
 public abstract class RemoveFixedAttributeNode extends FixedAttributeAccessNode {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java
index b669fa8b59..2856f8b339 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetAttributeNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -30,10 +31,14 @@ import com.oracle.truffle.api.object.FinalLocationException;
 import com.oracle.truffle.api.object.IncompatibleLocationException;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.data.RAttributable;
 
 public abstract class SetAttributeNode extends AttributeAccessNode {
 
+    @Child SetAttributeNode recursive;
+
     protected SetAttributeNode() {
     }
 
@@ -41,7 +46,7 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
         return SetAttributeNodeGen.create();
     }
 
-    public abstract void execute(DynamicObject attrs, String name, Object value);
+    public abstract void execute(Object attrs, String name, Object value);
 
     @Specialization(limit = "3", //
                     guards = {
@@ -100,6 +105,49 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
         receiver.define(name, value);
     }
 
+    protected static SpecialAttributesFunctions.SetSpecialAttributeNode createSpecAttrNode(String name) {
+        return SpecialAttributesFunctions.createSpecialAttributeNode(name);
+    }
+
+    @Specialization(limit = "3", //
+                    guards = {
+                                    "isSpecialAttributeNode.execute(name)",
+                                    "cachedName.equals(name)"
+                    })
+    @SuppressWarnings("unused")
+    protected void setSpecAttrInAttributable(RAttributable x, String name, Object value,
+                    @Cached("create()") SpecialAttributesFunctions.IsSpecialAttributeNode isSpecialAttributeNode,
+                    @Cached("name") String cachedName,
+                    @Cached("createSpecAttrNode(cachedName)") SpecialAttributesFunctions.SetSpecialAttributeNode setSpecAttrNode) {
+        setSpecAttrNode.execute(x, value);
+    }
+
+    @Specialization(contains = "setSpecAttrInAttributable", //
+                    guards = "isSpecialAttributeNode.execute(name)")
+    @SuppressWarnings("unused")
+    protected void setSpecAttrInAttributable(RAttributable x, String name, Object value,
+                    @Cached("create()") SpecialAttributesFunctions.IsSpecialAttributeNode isSpecialAttributeNode,
+                    @Cached("create()") SpecialAttributesFunctions.GenericSpecialAttributeNode genericSpecialAttrNode) {
+        genericSpecialAttrNode.execute(x, name, value);
+    }
+
+    @Specialization
+    protected void setAttrInAttributable(RAttributable x, String name, Object value,
+                    @Cached("create()") BranchProfile attrNullProfile) {
+        DynamicObject attributes = x.getAttributes();
+        if (attributes == null) {
+            attrNullProfile.enter();
+            attributes = x.initAttributes();
+        }
+
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create());
+        }
+
+        recursive.execute(attributes, name, value);
+    }
+
     /**
      * Try to find the given property in the shape. Also returns null when the value cannot be store
      * into the location.
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetClassAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetClassAttributeNode.java
deleted file mode 100644
index ef5dbf6859..0000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetClassAttributeNode.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.attributes;
-
-import com.oracle.truffle.api.dsl.Cached;
-import com.oracle.truffle.api.dsl.Specialization;
-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.runtime.RError;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributable;
-import com.oracle.truffle.r.runtime.data.RInteger;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.data.RVector;
-import com.oracle.truffle.r.runtime.nodes.RBaseNode;
-
-public abstract class SetClassAttributeNode extends RBaseNode {
-
-    public static SetClassAttributeNode create() {
-        return SetClassAttributeNodeGen.create();
-    }
-
-    public abstract void execute(RAttributable x, Object classAttr);
-
-    public void reset(RAttributable x) {
-        execute(x, RNull.instance);
-    }
-
-    @Specialization
-    protected <T> void handleVectorNullClass(RVector<T> vector, @SuppressWarnings("unused") RNull classAttr,
-                    @Cached("createClass()") RemoveFixedAttributeNode removeClassAttrNode,
-                    @Cached("createClass()") SetFixedAttributeNode setClassAttrNode,
-                    @Cached("create()") BranchProfile nullAttrProfile,
-                    @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
-                    @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile) {
-        handleVector(vector, null, removeClassAttrNode, setClassAttrNode, nullAttrProfile, nullClassProfile, notNullClassProfile);
-    }
-
-    @Specialization
-    protected <T> void handleVector(RVector<T> vector, RStringVector classAttr,
-                    @Cached("createClass()") RemoveFixedAttributeNode removeClassAttrNode,
-                    @Cached("createClass()") SetFixedAttributeNode setClassAttrNode,
-                    @Cached("create()") BranchProfile nullAttrProfile,
-                    @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
-                    @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile) {
-
-        DynamicObject attrs = vector.getAttributes();
-        if (attrs == null && classAttr != null && classAttr.getLength() != 0) {
-            nullAttrProfile.enter();
-            attrs = vector.initAttributes();
-        }
-        if (nullClassProfile.profile(attrs != null && (classAttr == null || classAttr.getLength() == 0))) {
-            removeAttributeMapping(vector, attrs, removeClassAttrNode);
-        } else if (notNullClassProfile.profile(classAttr != null && classAttr.getLength() != 0)) {
-            for (int i = 0; i < classAttr.getLength(); i++) {
-                String attr = classAttr.getDataAt(i);
-                if (RRuntime.CLASS_FACTOR.equals(attr)) {
-                    // TODO: Isn't this redundant when the same operation is done after the loop?
-                    setClassAttrNode.execute(attrs, classAttr);
-                    if (vector.getElementClass() != RInteger.class) {
-                        // N.B. there used to be conversion to integer under certain circumstances.
-                        // However, it seems that it was dead/obsolete code so it was removed.
-                        // Notes: this can only happen if the class is set by hand to some
-                        // non-integral vector, i.e. attr(doubles, 'class') <- 'factor'. GnuR also
-                        // does not update the 'class' attr with other, possibly
-                        // valid classes when it reaches this error.
-                        throw RError.error(RError.SHOW_CALLER2, RError.Message.ADDING_INVALID_CLASS, "factor");
-                    }
-                }
-            }
-            setClassAttrNode.execute(attrs, classAttr);
-        }
-    }
-
-    @Specialization
-    protected void handleAttributable(RAttributable x, @SuppressWarnings("unused") RNull classAttr) {
-        x.setClassAttr(null);
-    }
-
-    @Specialization
-    protected void handleAttributable(RAttributable x, RStringVector classAttr) {
-        x.setClassAttr(classAttr);
-    }
-
-    private static void removeAttributeMapping(RAttributable x, DynamicObject attrs, RemoveFixedAttributeNode removeClassAttrNode) {
-        if (attrs != null) {
-            removeClassAttrNode.execute(attrs);
-            if (attrs.isEmpty()) {
-                x.initAttributes(null);
-            }
-        }
-    }
-
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java
index 3f6b8b6beb..e427dc9cb4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.nodes.attributes;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -30,13 +31,22 @@ import com.oracle.truffle.api.object.FinalLocationException;
 import com.oracle.truffle.api.object.IncompatibleLocationException;
 import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.api.profiles.BranchProfile;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetSpecialAttributeNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributable;
 
 public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
 
+    @Child private SetFixedAttributeNode recursive;
+    @Child private SetSpecialAttributeNode setSpecialAttrNode;
+
+    private final boolean isSpecialAttribute;
+
     protected SetFixedAttributeNode(String name) {
         super(name);
+        this.isSpecialAttribute = SpecialAttributesFunctions.IsSpecialAttributeNode.isSpecialAttribute(name);
     }
 
     public static SetFixedAttributeNode create(String name) {
@@ -59,7 +69,7 @@ public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
         return SetFixedAttributeNode.create(RRuntime.CLASS_ATTR_KEY);
     }
 
-    public abstract void execute(DynamicObject attrs, Object value);
+    public abstract void execute(Object attr, Object value);
 
     @Specialization(limit = "3", //
                     guards = {"shapeCheck(shape, attrs)", "location != null"}, //
@@ -80,4 +90,29 @@ public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
         attrs.define(name, value);
     }
 
+    @Specialization
+    protected void setAttrInAttributable(RAttributable x, Object value,
+                    @Cached("create()") BranchProfile attrNullProfile) {
+        if (isSpecialAttribute) {
+            if (setSpecialAttrNode == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                setSpecialAttrNode = insert(SpecialAttributesFunctions.createSpecialAttributeNode(name));
+            }
+            setSpecialAttrNode.execute(x, value);
+        } else {
+            DynamicObject attributes = x.getAttributes();
+            if (attributes == null) {
+                attrNullProfile.enter();
+                attributes = x.initAttributes();
+            }
+
+            if (recursive == null) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                recursive = insert(create(name));
+            }
+            recursive.execute(attributes, value);
+        }
+
+    }
+
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java
new file mode 100644
index 0000000000..fa9375895a
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.attributes;
+
+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.object.DynamicObject;
+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.runtime.RError;
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributable;
+import com.oracle.truffle.r.runtime.data.RInteger;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+
+public final class SpecialAttributesFunctions {
+
+    public static final class IsSpecialAttributeNode extends RBaseNode {
+
+        private final BranchProfile namesProfile = BranchProfile.create();
+        private final BranchProfile dimProfile = BranchProfile.create();
+        private final BranchProfile dimNamesProfile = BranchProfile.create();
+        private final BranchProfile rowNamesProfile = BranchProfile.create();
+        private final BranchProfile classProfile = BranchProfile.create();
+
+        public static IsSpecialAttributeNode create() {
+            return new IsSpecialAttributeNode();
+        }
+
+        /**
+         * The fast-path method.
+         */
+        public boolean execute(String name) {
+            assert name.intern() == name;
+            if (name == RRuntime.NAMES_ATTR_KEY) {
+                namesProfile.enter();
+                return true;
+            } else if (name == RRuntime.DIM_ATTR_KEY) {
+                dimProfile.enter();
+                return true;
+            } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+                dimNamesProfile.enter();
+                return true;
+            } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+                rowNamesProfile.enter();
+                return true;
+            } else if (name == RRuntime.CLASS_ATTR_KEY) {
+                classProfile.enter();
+                return false;
+            }
+            return false;
+        }
+
+        /**
+         * The slow-path method.
+         */
+        public static boolean isSpecialAttribute(String name) {
+            assert name.intern() == name;
+            return name == RRuntime.NAMES_ATTR_KEY ||
+                            name == RRuntime.DIM_ATTR_KEY ||
+                            name == RRuntime.DIMNAMES_ATTR_KEY ||
+                            name == RRuntime.ROWNAMES_ATTR_KEY ||
+                            name == RRuntime.CLASS_ATTR_KEY;
+
+        }
+    }
+
+    public static final class GenericSpecialAttributeNode extends RBaseNode {
+
+        private final BranchProfile namesProfile = BranchProfile.create();
+        private final BranchProfile dimProfile = BranchProfile.create();
+        private final BranchProfile dimNamesProfile = BranchProfile.create();
+        private final BranchProfile rowNamesProfile = BranchProfile.create();
+
+        @Child private SetNamesAttributeNode namesAttrNode;
+        @Child private SetDimAttributeNode dimAttrNode;
+        @Child private SetDimNamesAttributeNode dimNamesAttrNode;
+        @Child private SetRowNamesAttributeNode rowNamesAttrNode;
+
+        public static GenericSpecialAttributeNode create() {
+            return new GenericSpecialAttributeNode();
+        }
+
+        public void execute(RAttributable x, String name, Object value) {
+            assert name.intern() == name;
+            if (name == RRuntime.NAMES_ATTR_KEY) {
+                namesProfile.enter();
+                if (namesAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    namesAttrNode = insert(SetNamesAttributeNode.create());
+                }
+                namesAttrNode.execute(x, value);
+            } else if (name == RRuntime.DIM_ATTR_KEY) {
+                dimProfile.enter();
+                if (dimAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    dimAttrNode = insert(SetDimAttributeNode.create());
+                }
+                dimAttrNode.execute(x, value);
+            } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+                dimNamesProfile.enter();
+                if (dimNamesAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    dimNamesAttrNode = insert(SetDimNamesAttributeNode.create());
+                }
+                dimNamesAttrNode.execute(x, value);
+            } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+                rowNamesProfile.enter();
+                if (rowNamesAttrNode == null) {
+                    CompilerDirectives.transferToInterpreterAndInvalidate();
+                    rowNamesAttrNode = insert(SetRowNamesAttributeNode.create());
+                }
+                rowNamesAttrNode.execute(x, value);
+            } else if (name == RRuntime.CLASS_ATTR_KEY) {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                throw RInternalError.unimplemented("The \"class\" attribute should be set using a separate method");
+            } else {
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+                throw RInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static SetSpecialAttributeNode createSpecialAttributeNode(String name) {
+        assert name.intern() == name;
+        if (name == RRuntime.NAMES_ATTR_KEY) {
+            return SetNamesAttributeNode.create();
+        } else if (name == RRuntime.DIM_ATTR_KEY) {
+            return SetDimAttributeNode.create();
+        } else if (name == RRuntime.DIMNAMES_ATTR_KEY) {
+            return SpecialAttributesFunctions.SetDimNamesAttributeNode.create();
+        } else if (name == RRuntime.ROWNAMES_ATTR_KEY) {
+            return SpecialAttributesFunctions.SetRowNamesAttributeNode.create();
+        } else if (name == RRuntime.CLASS_ATTR_KEY) {
+            throw RInternalError.unimplemented("The \"class\" attribute should be set using a separate method");
+        } else {
+            throw RInternalError.shouldNotReachHere();
+        }
+    }
+
+    public abstract static class SetSpecialAttributeNode extends RBaseNode {
+
+        public abstract void execute(RAttributable x, Object attrValue);
+
+    }
+
+    public abstract static class SetNamesAttributeNode extends SetSpecialAttributeNode {
+
+        public static SetNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetNamesAttributeNodeGen.create();
+        }
+
+        @Specialization
+        protected void setNamesInContainer(RAbstractContainer x, RStringVector names, @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setNames(names);
+        }
+    }
+
+    public abstract static class SetDimAttributeNode extends SetSpecialAttributeNode {
+
+        public static SetDimAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetDimAttributeNodeGen.create();
+        }
+
+        @Specialization
+        protected void setOneDimInContainer(RAbstractContainer x, Integer dim, @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setDimensions(new int[]{dim});
+        }
+
+        @Specialization
+        protected void setDimsInContainer(RAbstractContainer x, RAbstractIntVector dims, @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setDimensions(dims.materialize().getDataCopy());
+        }
+
+    }
+
+    public abstract static class SetDimNamesAttributeNode extends SetSpecialAttributeNode {
+
+        public static SetDimNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetDimNamesAttributeNodeGen.create();
+        }
+
+        @Specialization
+        protected void setDimNamesInContainer(RAbstractContainer x, RList dimNames, @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setDimNames(dimNames);
+        }
+
+    }
+
+    public abstract static class SetRowNamesAttributeNode extends SetSpecialAttributeNode {
+
+        public static SetRowNamesAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetRowNamesAttributeNodeGen.create();
+        }
+
+        @Specialization
+        protected void setRowNamesInContainer(RAbstractContainer x, RAbstractVector rowNames, @Cached("createClassProfile()") ValueProfile contClassProfile) {
+            RAbstractContainer xProfiled = contClassProfile.profile(x);
+            xProfiled.setRowNames(rowNames);
+        }
+
+    }
+
+    public abstract static class SetClassAttributeNode extends SetSpecialAttributeNode {
+
+        public static SetClassAttributeNode create() {
+            return SpecialAttributesFunctionsFactory.SetClassAttributeNodeGen.create();
+        }
+
+        public void reset(RAttributable x) {
+            execute(x, RNull.instance);
+        }
+
+        @Specialization
+        protected <T> void handleVectorNullClass(RVector<T> vector, @SuppressWarnings("unused") RNull classAttr,
+                        @Cached("createClass()") RemoveFixedAttributeNode removeClassAttrNode,
+                        @Cached("createClass()") SetFixedAttributeNode setClassAttrNode,
+                        @Cached("create()") BranchProfile nullAttrProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile) {
+            handleVector(vector, null, removeClassAttrNode, setClassAttrNode, nullAttrProfile, nullClassProfile, notNullClassProfile);
+        }
+
+        @Specialization
+        protected <T> void handleVector(RVector<T> vector, RStringVector classAttr,
+                        @Cached("createClass()") RemoveFixedAttributeNode removeClassAttrNode,
+                        @Cached("createClass()") SetFixedAttributeNode setClassAttrNode,
+                        @Cached("create()") BranchProfile nullAttrProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
+                        @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile) {
+
+            DynamicObject attrs = vector.getAttributes();
+            if (attrs == null && classAttr != null && classAttr.getLength() != 0) {
+                nullAttrProfile.enter();
+                attrs = vector.initAttributes();
+            }
+            if (nullClassProfile.profile(attrs != null && (classAttr == null || classAttr.getLength() == 0))) {
+                removeAttributeMapping(vector, attrs, removeClassAttrNode);
+            } else if (notNullClassProfile.profile(classAttr != null && classAttr.getLength() != 0)) {
+                for (int i = 0; i < classAttr.getLength(); i++) {
+                    String attr = classAttr.getDataAt(i);
+                    if (RRuntime.CLASS_FACTOR.equals(attr)) {
+                        // TODO: Isn't this redundant when the same operation is done after the
+                        // loop?
+                        setClassAttrNode.execute(attrs, classAttr);
+                        if (vector.getElementClass() != RInteger.class) {
+                            // N.B. there used to be conversion to integer under certain
+                            // circumstances.
+                            // However, it seems that it was dead/obsolete code so it was removed.
+                            // Notes: this can only happen if the class is set by hand to some
+                            // non-integral vector, i.e. attr(doubles, 'class') <- 'factor'. GnuR
+                            // also
+                            // does not update the 'class' attr with other, possibly
+                            // valid classes when it reaches this error.
+                            throw RError.error(RError.SHOW_CALLER2, RError.Message.ADDING_INVALID_CLASS, "factor");
+                        }
+                    }
+                }
+                setClassAttrNode.execute(attrs, classAttr);
+            }
+        }
+
+        @Specialization
+        protected void handleAttributable(RAttributable x, @SuppressWarnings("unused") RNull classAttr) {
+            x.setClassAttr(null);
+        }
+
+        @Specialization
+        protected void handleAttributable(RAttributable x, RStringVector classAttr) {
+            x.setClassAttr(classAttr);
+        }
+
+        private static void removeAttributeMapping(RAttributable x, DynamicObject attrs, RemoveFixedAttributeNode removeClassAttrNode) {
+            if (attrs != null) {
+                removeClassAttrNode.execute(attrs);
+                if (attrs.isEmpty()) {
+                    x.initAttributes(null);
+                }
+            }
+        }
+
+    }
+
+}
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 16ae928994..fe2840463b 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
@@ -102,7 +102,6 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
                 removeDimNames.execute(attributes);
                 result.setInternalDimNames(null);
             }
-            result.setInternalDimensions(null);
 
             RStringVector vecNames = source.getNames(attrSourceProfiles);
             if (hasNamesSource.profile(vecNames != null)) {
@@ -114,7 +113,6 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
         }
 
         putDim.execute(initAttributes.execute(result), RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
-        result.setInternalDimensions(newDimensions);
 
         RList newDimNames = source.getDimNames(attrSourceProfiles);
         if (hasDimNames.profile(newDimNames != null)) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
index 2c495a67ce..8dc96975eb 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java
@@ -19,8 +19,7 @@ import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNodeGen;
@@ -30,7 +29,6 @@ import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RS4Object;
 import com.oracle.truffle.r.runtime.data.RShareable;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
 
 // transcribed from src/main/attrib.c
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
index 0929f696f4..411ae2d4db 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java
@@ -17,7 +17,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
@@ -28,7 +28,6 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 
 // transcribed from src/main/objects.c
 public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
index 0b01117753..14ea322f9f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java
@@ -26,10 +26,10 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.SetClassAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -41,7 +41,6 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RS4Object;
-import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
@@ -91,7 +90,9 @@ public abstract class CastListNode extends CastBaseNode {
     }
 
     @Specialization
-    protected RList doLanguage(RLanguage operand, @Cached("create()") ArrayAttributeNode attrAttrAccess) {
+    protected RList doLanguage(RLanguage operand,
+                    @Cached("create()") ArrayAttributeNode attrAttrAccess,
+                    @Cached("create()") SetAttributeNode setAttrNode) {
         RList result = RContext.getRRuntimeASTAccess().asList(operand);
         DynamicObject operandAttrs = operand.getAttributes();
         if (operandAttrs != null) {
@@ -106,7 +107,7 @@ public abstract class CastListNode extends CastBaseNode {
 
                     setClassAttrNode.execute(result, attr.getValue());
                 } else {
-                    result.setAttr(attr.getName(), attr.getValue());
+                    setAttrNode.execute(result, attr.getName(), attr.getValue());
                 }
             }
         }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
index f5a84fb5c5..13475477da 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RChannel.java
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RLanguage;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index ff6d84758b..88c9bc23ee 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -41,7 +41,6 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributeProfiles;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
index a0f6d36b86..b699372cca 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java
@@ -30,7 +30,6 @@ import java.util.LinkedList;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.object.DynamicObject;
-import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.conn.ConnectionSupport.BaseRConnection;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
index 6d1ed9e4e3..2fcc8fee9e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java
@@ -142,7 +142,7 @@ public interface RAttributable extends RTypedValue {
      * initialized and will be just cleared, unless nullify is {@code true}.
      *
      * @param nullify Some implementations can force nullifying attributes instance if this flag is
-     *            set to {@code true}. Nullifying is not guaranteed for al implementations.
+     *            set to {@code true}. Nullifying is not guaranteed for all implementations.
      */
     default void resetAllAttributes(boolean nullify) {
         DynamicObject attributes = getAttributes();
@@ -164,6 +164,10 @@ public interface RAttributable extends RTypedValue {
         return (RStringVector) getAttr(profiles, RRuntime.CLASS_ATTR_KEY);
     }
 
+    default RStringVector getClassAttr() {
+        return (RStringVector) getAttr(RRuntime.CLASS_ATTR_KEY);
+    }
+
     /**
      * Returns {@code true} if and only if the value has a {@code class} attribute added explicitly.
      * When {@code true}, it is possible to call {@link RAttributable#getClassHierarchy()}.
@@ -172,6 +176,10 @@ public interface RAttributable extends RTypedValue {
         return getClassAttr(profiles) != null ? true : false;
     }
 
+    default boolean isObject() {
+        return getClassAttr() != null ? true : false;
+    }
+
     static void copyAttributes(RAttributable obj, DynamicObject attrs) {
         if (attrs == null) {
             return;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
index 70c54ef9df..5f109b8a52 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java
@@ -27,7 +27,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.object.DynamicObject;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
index 94d1d71fb4..65d16aef9b 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java
@@ -47,14 +47,14 @@ public class RExpression extends RListBase implements RAbstractVector {
 
     @Override
     protected RExpression internalCopy() {
-        return new RExpression(Arrays.copyOf(data, data.length), dimensions, null);
+        return new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null);
     }
 
     @Override
     protected RExpression internalDeepCopy() {
         // TOOD: only used for nested list updates, but still could be made faster (through a
         // separate AST node?)
-        RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), dimensions, null);
+        RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null);
         for (int i = 0; i < listCopy.getLength(); i++) {
             Object el = listCopy.getDataAt(i);
             if (el instanceof RVector) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
index dd1d78c819..cd52a76a92 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
@@ -196,7 +196,7 @@ public class RLanguage extends RSharingAttributeStorage implements RAbstractCont
     }
 
     @Override
-    public void setNames(RStringVector newNames) {
+    public final void setNames(RStringVector newNames) {
         if (list == null) {
             /* See getNames */
             RContext.getRRuntimeASTAccess().setNames(this, newNames);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
index dd97f6ea0d..8632d8f56d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java
@@ -44,14 +44,14 @@ public final class RList extends RListBase implements RAbstractListVector {
 
     @Override
     protected RList internalCopy() {
-        return new RList(Arrays.copyOf(data, data.length), dimensions, null);
+        return new RList(Arrays.copyOf(data, data.length), getDimensions(), null);
     }
 
     @Override
     protected RList internalDeepCopy() {
         // TOOD: only used for nested list updates, but still could be made faster (through a
         // separate AST node?)
-        RList listCopy = new RList(Arrays.copyOf(data, data.length), dimensions, null);
+        RList listCopy = new RList(Arrays.copyOf(data, data.length), getDimensions(), null);
         for (int i = 0; i < listCopy.getLength(); i++) {
             Object el = listCopy.getDataAt(i);
             if (el instanceof RVector) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
index fabe9e5c92..4b514edb83 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
@@ -329,7 +329,7 @@ public class RPairList extends RSharingAttributeStorage implements RAbstractCont
     }
 
     @Override
-    public void setNames(RStringVector newNames) {
+    public final void setNames(RStringVector newNames) {
         Object p = this;
         for (int i = 0; i < newNames.getLength() && !isNull(p); i++) {
             RPairList pList = (RPairList) p;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index d0983a3caf..06c7279cc4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -28,12 +28,14 @@ import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.object.DynamicObject;
+import com.oracle.truffle.api.object.Location;
+import com.oracle.truffle.api.object.Property;
+import com.oracle.truffle.api.object.Shape;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.SuppressFBWarnings;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -60,7 +62,8 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     private static final RStringVector implicitClassHeaderMatrix = RDataFactory.createStringVector(new String[]{RType.Matrix.getName()}, true);
 
     protected boolean complete; // "complete" means: does not contain NAs
-    protected int[] dimensions;
+    private Shape attrShape;
+    private Location dimensionsLoc;
     protected RStringVector names;
     private RList dimNames;
     // cache rownames for data frames as they are accessed at every data frame access
@@ -68,7 +71,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     protected RVector(boolean complete, int length, int[] dimensions, RStringVector names) {
         this.complete = complete;
-        this.dimensions = dimensions;
+        // this.dimensions = dimensions;
         assert names != this;
         this.names = names;
         this.rowNames = RNull.instance;
@@ -93,6 +96,35 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
                 initAttributes(RAttributesLayout.createDim(RDataFactory.createIntVector(dimensions, true)));
             }
         }
+        updateLocationsFromAttrs();
+    }
+
+    private void updateLocationsFromAttrs() {
+        if (attributes == null) {
+            attrShape = null;
+            dimensionsLoc = null;
+        } else if (attributes.getShape() != attrShape) {
+            attrShape = attributes.getShape();
+            Property prop = attrShape.getProperty(RRuntime.DIM_ATTR_KEY);
+            if (prop == null) {
+                dimensionsLoc = null;
+            } else {
+                dimensionsLoc = prop.getLocation();
+            }
+            // TODO: the same for the other special attributes
+        }
+    }
+
+    private int[] getDimensionsFromAttrs() {
+        // Sync the shape
+        updateLocationsFromAttrs();
+
+        if (dimensionsLoc == null) {
+            return null;
+        } else {
+            RIntVector dims = (RIntVector) dimensionsLoc.get(attributes);
+            return dims.getInternalStore();
+        }
     }
 
     /**
@@ -127,11 +159,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     }
 
     public final int[] getInternalDimensions() {
-        return dimensions;
-    }
-
-    public final void setInternalDimensions(int[] newDimensions) {
-        dimensions = newDimensions;
+        return getDimensionsFromAttrs();
     }
 
     public final RStringVector getInternalNames() {
@@ -359,7 +387,8 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             if (newNames.getLength() > this.getLength()) {
                 throw RError.error(invokingNode, RError.Message.ATTRIBUTE_VECTOR_SAME_LENGTH, RRuntime.NAMES_ATTR_KEY, newNames.getLength(), this.getLength());
             }
-            if (this.dimensions != null && dimensions.length == 1) {
+            int[] dimensions = getDimensionsFromAttrs();
+            if (dimensions != null && dimensions.length == 1) {
                 // for one dimensional array, "names" is really "dimnames[[1]]" (see R documentation
                 // for "names" function)
                 RList newDimNames = RDataFactory.createList(new Object[]{newNames});
@@ -409,6 +438,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             removeAttributeMapping(RRuntime.DIMNAMES_ATTR_KEY);
             this.dimNames = null;
         } else if (newDimNames != null) {
+            int[] dimensions = getDimensionsFromAttrs();
             if (dimensions == null) {
                 throw RError.error(invokingNode, RError.Message.DIMNAMES_NONARRAY);
             }
@@ -476,22 +506,27 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     @Override
     public final boolean hasDimensions() {
-        return dimensions != null;
+        // Sync the shape
+        updateLocationsFromAttrs();
+
+        return dimensionsLoc != null;
     }
 
     @Override
     public final boolean isMatrix() {
+        int[] dimensions = getDimensionsFromAttrs();
         return dimensions != null && dimensions.length == 2;
     }
 
     @Override
     public final boolean isArray() {
+        int[] dimensions = getDimensionsFromAttrs();
         return dimensions != null && dimensions.length > 0;
     }
 
     @Override
     public final int[] getDimensions() {
-        return dimensions;
+        return getDimensionsFromAttrs();
     }
 
     /**
@@ -505,7 +540,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         } else {
             putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
         }
-        this.dimensions = newDimensions;
     }
 
     @Override
@@ -521,7 +555,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             verifyDimensions(getLength(), newDimensions, invokingNode);
             putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(newDimensions, RDataFactory.COMPLETE_VECTOR));
         }
-        this.dimensions = newDimensions;
     }
 
     @Override
@@ -569,7 +602,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         result.names = this.names;
         result.dimNames = this.dimNames;
         result.rowNames = this.rowNames;
-        result.dimensions = this.dimensions;
         if (this.attributes != null) {
             result.initAttributes(RAttributesLayout.copy(this.attributes));
         }
@@ -668,7 +700,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         assert (this.names == null);
         assert (this.dimNames == null);
         assert (this.rowNames == RNull.instance);
-        assert (this.dimensions == null);
+        assert (!hasDimensions());
         assert (this.attributes == null || this.attributes.size() == 0) : this.attributes.size();
         if (vector.getDimensions() == null || vector.getDimensions().length != 1) {
             // only assign name attribute if it's not represented as dimnames (as is the case for
@@ -677,7 +709,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         }
         this.dimNames = vector.getDimNames(attrProfiles);
         this.rowNames = vector.getRowNames(attrProfiles);
-        this.dimensions = vector.getDimensions();
         DynamicObject vecAttributes = vector.getAttributes();
         if (vecAttributes != null) {
             initAttributes(RAttributesLayout.copy(vecAttributes));
@@ -697,7 +728,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         }
         this.dimNames = vector.getDimNames();
         this.rowNames = vector.getRowNames();
-        this.dimensions = vector.getDimensions();
         DynamicObject vecAttributes = vector.getAttributes();
         if (vecAttributes != null) {
             initAttributes(RAttributesLayout.copy(vecAttributes));
@@ -711,7 +741,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         // it's meant to be used on a "fresh" vector with only dimensions potentially set
         assert (this.names == null);
         assert (this.dimNames == null);
-        assert (this.dimensions == null);
+        assert (!hasDimensions());
         assert (this.attributes == null);
         // for some reason, names is copied first, then dims, then dimnames
         if (vector.getDimensions() == null || vector.getDimensions().length != 1) {
@@ -724,7 +754,8 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     }
 
     public final boolean copyNamesFrom(RAttributeProfiles attrProfiles, RAbstractVector vector) {
-        if (this.dimensions == null) {
+        int[] dimensions = getDimensionsFromAttrs();
+        if (dimensions == null) {
             RStringVector vecNames = vector.getNames(attrProfiles);
             if (vecNames != null) {
                 this.setNames(vecNames);
@@ -794,13 +825,12 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
     @TruffleBoundary
     public final void resetDimensions(int[] newDimensions) {
         // reset all attributes other than dimensions;
-        this.dimensions = newDimensions;
         // whether we nullify dimensions or re-set them to a different value, names and dimNames
         // must be reset
         this.names = null;
         this.dimNames = null;
-        if (this.dimensions != null) {
-            putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(this.dimensions, true));
+        if (newDimensions != null) {
+            putAttribute(RRuntime.DIM_ATTR_KEY, RDataFactory.createIntVector(newDimensions, true));
         } else {
             // nullifying dimensions does not reset regular attributes
             if (this.attributes != null) {
@@ -813,7 +843,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
 
     @Override
     public final void resetAllAttributes(boolean nullify) {
-        this.dimensions = null;
         this.names = null;
         this.dimNames = null;
         this.rowNames = RNull.instance;
-- 
GitLab