From 96faea94295f98ef203d773bd9a107c3e9db0937 Mon Sep 17 00:00:00 2001
From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com>
Date: Wed, 23 Nov 2016 15:37:47 +0100
Subject: [PATCH] Using constant layouts

---
 .../library/methods/MethodsListDispatch.java  |  10 +-
 .../truffle/r/nodes/builtin/base/Combine.java |   2 +-
 .../r/nodes/builtin/base/IsTypeFunctions.java |   4 +-
 .../truffle/r/nodes/builtin/base/Repeat.java  |   6 +-
 .../r/nodes/builtin/base/StandardGeneric.java |   6 +-
 .../r/nodes/builtin/base/Transpose.java       |   6 +-
 .../r/nodes/builtin/base/UpdateDim.java       |   4 +-
 .../r/nodes/builtin/base/UpdateDimNames.java  |   6 +-
 .../base/printer/ValuePrinterNode.java        |   6 +-
 .../r/nodes/access/AccessSlotNode.java        |   8 +-
 .../r/nodes/access/UpdateSlotNode.java        |   8 +-
 .../vector/CachedExtractVectorNode.java       |   8 +-
 .../nodes/attributes/ArrayAttributeNode.java  | 100 ++++++
 .../r/nodes/attributes/AttributeRemover.java  |  56 ----
 .../nodes/attributes/CopyAttributesNode.java  |  14 +-
 .../attributes/CopyOfRegAttributesNode.java   |   6 +-
 .../attributes/FixedAttributeAccessNode.java  |  67 ++++
 .../attributes/FixedAttributeGetter.java      |  84 -----
 .../attributes/FixedAttributeSetter.java      |  75 -----
 .../attributes/GetFixedAttributeNode.java     |  72 +++++
 .../attributes/SetFixedAttributeNode.java     |  86 +++++
 .../attributes/UnaryCopyAttributesNode.java   |   6 +-
 .../r/nodes/function/ClassHierarchyNode.java  |   6 +-
 .../truffle/r/nodes/helpers/RFactorNodes.java |   6 +-
 .../r/nodes/objects/GetS4DataSlot.java        |  14 +-
 .../truffle/r/nodes/objects/LoadMethod.java   |  10 +-
 .../truffle/r/nodes/objects/NewObject.java    |   4 +-
 .../r/runtime/data/RAttributesLayout.java     | 294 +++++++-----------
 28 files changed, 515 insertions(+), 459 deletions(-)
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java
 delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeRemover.java
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeAccessNode.java
 delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeGetter.java
 delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeSetter.java
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
 create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.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 57f85cee57..882a6fcf1d 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
@@ -23,7 +23,7 @@ import com.oracle.truffle.r.nodes.access.AccessSlotNode;
 import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeGetter;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyScalarNodeGen;
@@ -93,15 +93,15 @@ public class MethodsListDispatch {
 
     public abstract static class R_getClassFromCache extends RExternalBuiltinNode.Arg2 {
 
-        protected FixedAttributeGetter createPckgAttrAccess() {
-            return FixedAttributeGetter.create(RRuntime.PCKG_ATTR_KEY);
+        protected GetFixedAttributeNode createPckgAttrAccess() {
+            return GetFixedAttributeNode.create(RRuntime.PCKG_ATTR_KEY);
         }
 
         @Specialization
         @TruffleBoundary
         protected Object callGetClassFromCache(RAbstractStringVector klass, REnvironment table, //
-                        @Cached("createPckgAttrAccess()") FixedAttributeGetter klassPckgAttrAccess, //
-                        @Cached("createPckgAttrAccess()") FixedAttributeGetter valPckgAttrAccess) {
+                        @Cached("createPckgAttrAccess()") GetFixedAttributeNode klassPckgAttrAccess, //
+                        @Cached("createPckgAttrAccess()") GetFixedAttributeNode valPckgAttrAccess) {
             String klassString = klass.getLength() == 0 ? RRuntime.STRING_NA : klass.getDataAt(0);
 
             Object value = table.get(klassString);
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 ade18c55db..431cc73c7d 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,7 @@ import com.oracle.truffle.api.nodes.ExplodeLoop;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeSetter;
+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/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
index 196cfc312c..9601eb92e0 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java
@@ -37,6 +37,7 @@ import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.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.nodes.helpers.InheritsCheckNode;
@@ -481,6 +482,7 @@ public class IsTypeFunctions {
         private final ConditionProfile attrEmpty = ConditionProfile.createBinaryProfile();
         private final ConditionProfile attrNames = ConditionProfile.createBinaryProfile();
         private final BranchProfile namesAttrProfile = BranchProfile.create();
+        @Child private GetFixedAttributeNode namesGetter = GetFixedAttributeNode.createNames();
 
         @Override
         protected void createCasts(CastBuilder casts) {
@@ -519,7 +521,7 @@ public class IsTypeFunctions {
             if (attrNull.profile(attributes == null) || attrEmpty.profile(attributes.size() == 0)) {
                 return true;
             } else {
-                return attributes.size() == 1 && attrNames.profile(RAttributesLayout.getNames(attributes, namesAttrProfile) != null);
+                return attributes.size() == 1 && attrNames.profile(namesGetter.execute(attributes) != null);
             }
         }
     }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
index 40921ec947..743d510865 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java
@@ -37,7 +37,7 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeSetter;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -152,7 +152,7 @@ public abstract class Repeat extends RBuiltinNode {
     @Specialization(guards = {"each > 1", "hasNames(x)"})
     protected RAbstractVector repEachNames(RAbstractVector x, RAbstractIntVector times, int lengthOut, int each,
                     @Cached("create()") InitAttributesNode initAttributes,
-                    @Cached("createNames()") FixedAttributeSetter putNames) {
+                    @Cached("createNames()") SetFixedAttributeNode putNames) {
         if (times.getLength() > 1) {
             errorBranch.enter();
             throw invalidTimes();
@@ -175,7 +175,7 @@ public abstract class Repeat extends RBuiltinNode {
     @Specialization(guards = {"each <= 1", "hasNames(x)"})
     protected RAbstractVector repNoEachNames(RAbstractVector x, RAbstractIntVector times, int lengthOut, @SuppressWarnings("unused") int each,
                     @Cached("create()") InitAttributesNode initAttributes,
-                    @Cached("createNames()") FixedAttributeSetter putNames) {
+                    @Cached("createNames()") SetFixedAttributeNode putNames) {
         RStringVector names;
         RVector<?> r;
         if (lengthOutOrTimes.profile(!RRuntime.isNA(lengthOut))) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
index b94bd8537f..08c9e57b8c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java
@@ -30,7 +30,7 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeGetter;
+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.nodes.function.ClassHierarchyScalarNode;
@@ -59,7 +59,7 @@ public abstract class StandardGeneric extends RBuiltinNode {
 
     // TODO: for now, we always go through generic dispatch
 
-    @Child private FixedAttributeGetter genericAttrAccess;
+    @Child private GetFixedAttributeNode genericAttrAccess;
     @Child private FrameFunctions.SysFunction sysFunction;
     @Child private LocalReadVariableNode readMTableFirst = LocalReadVariableNode.create(RRuntime.DOT_ALL_MTABLE, true);
     @Child private LocalReadVariableNode readSigLength = LocalReadVariableNode.create(RRuntime.DOT_SIG_LENGTH, true);
@@ -136,7 +136,7 @@ public abstract class StandardGeneric extends RBuiltinNode {
         }
         if (genericAttrAccess == null) {
             CompilerDirectives.transferToInterpreterAndInvalidate();
-            genericAttrAccess = insert(FixedAttributeGetter.create(RRuntime.GENERIC_ATTR_KEY));
+            genericAttrAccess = insert(GetFixedAttributeNode.create(RRuntime.GENERIC_ATTR_KEY));
         }
         genObj = genericAttrAccess.execute(attributes);
         if (genObj == null) {
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 5bc24500f2..ec945bb76c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
@@ -25,7 +25,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeSetter;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
@@ -59,8 +59,8 @@ public abstract class Transpose extends RBuiltinNode {
 
     @Child private CopyOfRegAttributesNode copyRegAttributes = CopyOfRegAttributesNodeGen.create();
     @Child private InitAttributesNode initAttributes = InitAttributesNode.create();
-    @Child private FixedAttributeSetter putDimensions = FixedAttributeSetter.createDim();
-    @Child private FixedAttributeSetter putDimNames = FixedAttributeSetter.createDimNames();
+    @Child private SetFixedAttributeNode putDimensions = SetFixedAttributeNode.createDim();
+    @Child private SetFixedAttributeNode putDimNames = SetFixedAttributeNode.createDimNames();
 
     public abstract Object execute(RAbstractVector o);
 
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 1f6477c328..30235da0ad 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
@@ -29,7 +29,7 @@ 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.FixedAttributeSetter;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -61,7 +61,7 @@ public abstract class UpdateDim extends RBuiltinNode {
 
     @Specialization
     protected RAbstractVector updateDim(RAbstractVector vector, RAbstractIntVector dimensions,
-                    @Cached("createDim()") FixedAttributeSetter putDimensions,
+                    @Cached("createDim()") SetFixedAttributeNode putDimensions,
                     @Cached("create()") InitAttributesNode initAttributes) {
         RIntVector dimensionsMaterialized = dimensions.materialize();
         int[] dimsData = dimensionsMaterialized.getDataCopy();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
index 0e646e299b..7df41d019c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java
@@ -31,7 +31,7 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.FixedAttributeRemover;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeSetter;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
@@ -116,7 +116,7 @@ public abstract class UpdateDimNames extends RBuiltinNode {
 
     @Specialization(guards = "list.getLength() > 0")
     protected RAbstractContainer updateDimnames(RAbstractContainer container, RList list, //
-                    @Cached("createDimNames()") FixedAttributeSetter attrSetter) {
+                    @Cached("createDimNames()") SetFixedAttributeNode attrSetter) {
         RAbstractContainer result = (RAbstractContainer) container.getNonShared();
         setDimNames(result, convertToListOfStrings(list), attrSetter);
         return result;
@@ -128,7 +128,7 @@ public abstract class UpdateDimNames extends RBuiltinNode {
         throw RError.error(this, RError.Message.DIMNAMES_LIST);
     }
 
-    private void setDimNames(RAbstractContainer container, RList newDimNames, FixedAttributeSetter attrSetter) {
+    private void setDimNames(RAbstractContainer container, RList newDimNames, SetFixedAttributeNode attrSetter) {
         assert newDimNames != null;
         if (isRVectorProfile.profile(container instanceof RVector)) {
             RVector<?> vector = (RVector<?>) container;
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 cc90861939..cbcb5e2af9 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
@@ -37,7 +37,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.object.DynamicObject;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeSetter;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode;
 import com.oracle.truffle.r.nodes.builtin.base.InheritsBuiltin;
 import com.oracle.truffle.r.nodes.builtin.base.InheritsBuiltinNodeGen;
@@ -102,8 +102,8 @@ public final class ValuePrinterNode extends RBaseNode {
         @Child private Node isBoxedNode = com.oracle.truffle.api.interop.Message.IS_BOXED.createNode();
         @Child private Node unboxNode = com.oracle.truffle.api.interop.Message.UNBOX.createNode();
         @Child private Node keysNode = com.oracle.truffle.api.interop.Message.KEYS.createNode();
-        @Child private FixedAttributeSetter namesAttrSetter = FixedAttributeSetter.createNames();
-        @Child private FixedAttributeSetter isTruffleObjAttrSetter = FixedAttributeSetter.create("is.truffle.object");
+        @Child private SetFixedAttributeNode namesAttrSetter = SetFixedAttributeNode.createNames();
+        @Child private SetFixedAttributeNode isTruffleObjAttrSetter = SetFixedAttributeNode.create("is.truffle.object");
 
         public Object convert(VirtualFrame frame, TruffleObject obj) {
             class RStringWrapper extends TruffleObjectWrapper implements RAbstractStringVector {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
index daa0054114..e1cad7d5fd 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java
@@ -20,7 +20,7 @@ import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.r.nodes.RASTUtils;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeGetter;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
 import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
@@ -61,8 +61,8 @@ public abstract class AccessSlotNode extends RNode {
         this.asOperator = asOperator;
     }
 
-    protected FixedAttributeGetter createAttrAccess(String name) {
-        return FixedAttributeGetter.create(name);
+    protected GetFixedAttributeNode createAttrAccess(String name) {
+        return GetFixedAttributeNode.create(name);
     }
 
     private Object getSlotS4Internal(RAttributable object, String name, Object value) {
@@ -112,7 +112,7 @@ public abstract class AccessSlotNode extends RNode {
 
     @Specialization(guards = {"slotAccessAllowed(object)", "name == cachedName"})
     protected Object getSlotS4Cached(RAttributable object, @SuppressWarnings("unused") String name, @Cached("name") String cachedName,
-                    @Cached("createAttrAccess(cachedName)") FixedAttributeGetter attrAccess, //
+                    @Cached("createAttrAccess(cachedName)") GetFixedAttributeNode attrAccess, //
                     @Cached("create()") InitAttributesNode initAttrNode) {
         Object value = attrAccess.execute(initAttrNode.execute(object));
         return getSlotS4Internal(object, cachedName, value);
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
index d94654d6a2..cecfe984a9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java
@@ -18,7 +18,7 @@ import com.oracle.truffle.api.dsl.NodeChild;
 import com.oracle.truffle.api.dsl.NodeChildren;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.RASTUtils;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeSetter;
+import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.InitAttributesNode;
 import com.oracle.truffle.r.runtime.RCaller;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -35,8 +35,8 @@ public abstract class UpdateSlotNode extends RNode {
 
     public abstract Object executeUpdate(Object object, String name, Object value);
 
-    protected FixedAttributeSetter createAttrUpdate(String name) {
-        return FixedAttributeSetter.create(name);
+    protected SetFixedAttributeNode createAttrUpdate(String name) {
+        return SetFixedAttributeNode.create(name);
     }
 
     private static Object prepareValue(Object value) {
@@ -47,7 +47,7 @@ public abstract class UpdateSlotNode extends RNode {
     @Specialization(guards = {"!isData(name)", "name == cachedName"})
     protected Object updateSlotS4Cached(RAttributable object, String name, Object value, //
                     @Cached("name") String cachedName, //
-                    @Cached("createAttrUpdate(cachedName)") FixedAttributeSetter attributeUpdate, //
+                    @Cached("createAttrUpdate(cachedName)") SetFixedAttributeNode attributeUpdate, //
                     @Cached("create()") InitAttributesNode initAttributes) {
         attributeUpdate.execute(initAttributes.execute(object), prepareValue(value));
         return object;
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 6938fee71a..668650b5e1 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
@@ -34,8 +34,8 @@ 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.GetAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeGetter;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeSetter;
+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;
@@ -435,8 +435,8 @@ final class CachedExtractVectorNode extends CachedVectorNode {
 
     protected abstract static class SetNamesNode extends Node {
 
-        @Child private FixedAttributeSetter namesAttrSetter = FixedAttributeSetter.create(RRuntime.NAMES_ATTR_KEY);
-        @Child private FixedAttributeGetter namesAttrGetter = FixedAttributeGetter.create(RRuntime.NAMES_ATTR_KEY);
+        @Child private SetFixedAttributeNode namesAttrSetter = SetFixedAttributeNode.create(RRuntime.NAMES_ATTR_KEY);
+        @Child private GetFixedAttributeNode namesAttrGetter = GetFixedAttributeNode.create(RRuntime.NAMES_ATTR_KEY);
 
         public abstract void execute(RVector<?> container, Object newNames);
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java
new file mode 100644
index 0000000000..7536e742e9
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/ArrayAttributeNode.java
@@ -0,0 +1,100 @@
+/*
+ * 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 java.util.List;
+
+import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.nodes.ExplodeLoop;
+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.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout.AttrsLayout;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout.ConstantShapesAndLocations;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
+
+public abstract class ArrayAttributeNode extends RBaseNode {
+
+    protected static final int CACHE_LIMIT = RAttributesLayout.LAYOUTS.length;
+
+    private final ConditionProfile[] loopProfiles;
+
+    protected ArrayAttributeNode() {
+        this.loopProfiles = new ConditionProfile[RAttributesLayout.LAYOUTS.length];
+        for (int i = 0; i < RAttributesLayout.LAYOUTS.length; i++) {
+            loopProfiles[i] = ConditionProfile.createBinaryProfile();
+        }
+    }
+
+    public static ArrayAttributeNode create() {
+        return ArrayAttributeNodeGen.create();
+    }
+
+    public abstract Object[] execute(DynamicObject attrs);
+
+    @ExplodeLoop
+    protected AttrsLayout findLayout(DynamicObject attrs) {
+        Shape attrsShape = attrs.getShape();
+        for (int i = 0; i < RAttributesLayout.LAYOUTS.length; i++) {
+            AttrsLayout attrsLayout = RAttributesLayout.LAYOUTS[i];
+            if (loopProfiles[i].profile(attrsLayout.shape == attrsShape)) {
+                return attrsLayout;
+            }
+        }
+        return null;
+    }
+
+    @Specialization(limit = "CACHE_LIMIT", guards = {"attrsLayout != null", "attrsLayout.shape.check(attrs)"})
+    @ExplodeLoop
+    protected RAttribute[] getArrayFromConstantLayouts(DynamicObject attrs, @Cached("findLayout(attrs)") AttrsLayout attrsLayout) {
+        Property[] props = attrsLayout.properties;
+        RAttribute[] result = new RAttribute[props.length];
+        for (int i = 0; i < props.length; i++) {
+            result[i] = new RAttributesLayout.AttrInstance((String) props[i].getKey(), props[i].get(attrs, attrsLayout.shape));
+        }
+
+        return result;
+    }
+
+    @Specialization(contains = "getArrayFromConstantLayouts")
+    protected RAttribute[] getArrayFallback(DynamicObject attrs) {
+        Shape shape = attrs.getShape();
+        List<Property> props = shape.getPropertyList();
+        RAttribute[] result = new RAttribute[props.size()];
+        int i = 0;
+        for (Property p : props) {
+            result[i] = new RAttributesLayout.AttrInstance((String) p.getKey(), p.get(attrs, shape));
+            i++;
+        }
+
+        return result;
+
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeRemover.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeRemover.java
deleted file mode 100644
index 64bcee3231..0000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeRemover.java
+++ /dev/null
@@ -1,56 +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.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.nodes.RBaseNode;
-
-public abstract class AttributeRemover extends RBaseNode {
-
-    protected AttributeRemover() {
-    }
-
-    public static AttributeRemover create() {
-        return AttributeRemoverNodeGen.create();
-    }
-
-    public abstract boolean execute(DynamicObject attrs, String name);
-
-    @Specialization(limit = "5", guards = "name.equals(cachedName)")
-    @SuppressWarnings("unused")
-    protected boolean handleCached(DynamicObject attrs, String name,
-                    @Cached("name") String cachedName,
-                    @Cached("create(name)") FixedAttributeRemover attrRemover) {
-        return attrRemover.execute(attrs);
-    }
-
-    @Specialization
-    protected boolean handleNonCached(DynamicObject attrs, String name) {
-        return attrs.delete(name);
-    }
-}
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 a580f470cb..358d51c76f 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
@@ -116,9 +116,9 @@ public abstract class CopyAttributesNode extends RBaseNode {
                     @Cached("createDim()") FixedAttributeRemover removeDim,
                     @Cached("createDimNames()") FixedAttributeRemover removeDimNames,
                     @Cached("create()") InitAttributesNode initAttributes,
-                    @Cached("createNames()") FixedAttributeSetter putNames,
-                    @Cached("createDim()") FixedAttributeSetter putDim,
-                    @Cached("createDimNames()") FixedAttributeSetter putDimNames,
+                    @Cached("createNames()") SetFixedAttributeNode putNames,
+                    @Cached("createDim()") SetFixedAttributeNode putDim,
+                    @Cached("createDimNames()") SetFixedAttributeNode putDimNames,
                     @Cached("create()") BranchProfile leftHasDimensions,
                     @Cached("create()") BranchProfile rightHasDimensions,
                     @Cached("create()") BranchProfile noDimensions,
@@ -204,8 +204,8 @@ public abstract class CopyAttributesNode extends RBaseNode {
                     @Cached("create()") BranchProfile leftHasDimensions, //
                     @Cached("create()") BranchProfile rightHasDimensions, //
                     @Cached("create()") BranchProfile noDimensions, //
-                    @Cached("createNames()") FixedAttributeSetter putNames, //
-                    @Cached("createDim()") FixedAttributeSetter putDim, //
+                    @Cached("createNames()") SetFixedAttributeNode putNames, //
+                    @Cached("createDim()") SetFixedAttributeNode putDim, //
                     @Cached("create()") InitAttributesNode initAttributes, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNames, //
                     @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
@@ -259,8 +259,8 @@ public abstract class CopyAttributesNode extends RBaseNode {
                     @Cached("create()") BranchProfile leftHasDimensions, //
                     @Cached("create()") BranchProfile rightHasDimensions, //
                     @Cached("create()") BranchProfile noDimensions, //
-                    @Cached("createNames()") FixedAttributeSetter putNames, //
-                    @Cached("createDim()") FixedAttributeSetter putDim, //
+                    @Cached("createNames()") SetFixedAttributeNode putNames, //
+                    @Cached("createDim()") SetFixedAttributeNode putDim, //
                     @Cached("create()") InitAttributesNode initAttributes, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNames, //
                     @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
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 364330f193..7b6897b18b 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
@@ -48,9 +48,9 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode {
 
     private final ConditionProfile sizeOneProfile = ConditionProfile.createBinaryProfile();
 
-    @Child private FixedAttributeGetter dimAttrGetter = FixedAttributeGetter.createDim();
-    @Child private FixedAttributeGetter namesAttrGetter = FixedAttributeGetter.createNames();
-    @Child private FixedAttributeGetter classAttrGetter = FixedAttributeGetter.createClass();
+    @Child private GetFixedAttributeNode dimAttrGetter = GetFixedAttributeNode.createDim();
+    @Child private GetFixedAttributeNode namesAttrGetter = GetFixedAttributeNode.createNames();
+    @Child private GetFixedAttributeNode classAttrGetter = GetFixedAttributeNode.createClass();
 
     public abstract void execute(RAbstractVector source, RVector<?> target);
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeAccessNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeAccessNode.java
new file mode 100644
index 0000000000..ce1af1cfc3
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeAccessNode.java
@@ -0,0 +1,67 @@
+/*
+ * 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.nodes.ExplodeLoop;
+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.r.runtime.nodes.RBaseNode;
+
+public class FixedAttributeAccessNode extends RBaseNode {
+
+    protected static final int CACHE_LIMIT = 3;
+
+    protected final String name;
+    protected final Shape[] constantShapes;
+    protected final Location[] constantLocations;
+    private final ConditionProfile[] loopProfiles;
+
+    protected FixedAttributeAccessNode(String name, Shape[] constantShapes, Location[] constantLocations) {
+        assert constantShapes.length == constantLocations.length;
+        this.name = name;
+        this.constantShapes = constantShapes;
+        this.constantLocations = constantLocations;
+        this.loopProfiles = new ConditionProfile[constantShapes.length];
+        for (int i = 0; i < constantShapes.length; i++) {
+            loopProfiles[i] = ConditionProfile.createBinaryProfile();
+        }
+    }
+
+    @ExplodeLoop
+    protected final int findShapeIndex(DynamicObject attrs) {
+        Shape shape = attrs.getShape();
+        for (int i = 0; i < constantShapes.length; i++) {
+            if (loopProfiles[i].profile(constantShapes[i] == shape)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    protected boolean shapeCheck(DynamicObject attrs, int shapeIndex) {
+        return constantShapes[shapeIndex].check(attrs);
+    }
+
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeGetter.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeGetter.java
deleted file mode 100644
index 6bda2a8b3b..0000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeGetter.java
+++ /dev/null
@@ -1,84 +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.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.Property;
-import com.oracle.truffle.api.object.Shape;
-import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.nodes.RBaseNode;
-
-public abstract class FixedAttributeGetter extends RBaseNode {
-
-    protected final String name;
-    protected final Shape constantShape;
-    protected final Location constantLocation;
-
-    protected FixedAttributeGetter(String name, Shape constantShape, Location constantLocation) {
-        this.name = name;
-        this.constantShape = constantShape;
-        this.constantLocation = constantLocation;
-        assert constantShape == null || constantLocation != null;
-    }
-
-    public static FixedAttributeGetter create(String name) {
-        return FixedAttributeGetterNodeGen.create(name, null, null);
-    }
-
-    public static FixedAttributeGetter createNames() {
-        return FixedAttributeGetter.create(RRuntime.NAMES_ATTR_KEY);
-    }
-
-    public static FixedAttributeGetter createDim() {
-        return FixedAttributeGetter.create(RRuntime.DIM_ATTR_KEY);
-    }
-
-    public static FixedAttributeGetter createClass() {
-        return FixedAttributeGetter.create(RRuntime.CLASS_ATTR_KEY);
-    }
-
-    public abstract Object execute(DynamicObject attrs);
-
-    @Specialization(guards = "attrs.getShape()==constantShape")
-    protected Object getFromConstantLocation(DynamicObject attrs) {
-        return constantLocation.get(attrs);
-    }
-
-    @Specialization(contains = "getFromConstantLocation", guards = {"cachedProperty != null", "attrs.getShape() == cachedShape"})
-    protected Object getFromCachedLocation(DynamicObject attrs,
-                    @SuppressWarnings("unused") @Cached("attrs.getShape()") Shape cachedShape,
-                    @Cached("cachedShape.getProperty(name)") Property cachedProperty) {
-        return cachedProperty.getLocation().get(attrs);
-    }
-
-    @Specialization(contains = "getFromCachedLocation")
-    protected Object getFromObject(DynamicObject attrs, @Cached("create()") GetAttributeNode getter) {
-        return getter.execute(attrs, name);
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeSetter.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeSetter.java
deleted file mode 100644
index 0927a86f97..0000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/FixedAttributeSetter.java
+++ /dev/null
@@ -1,75 +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.object.DynamicObject;
-import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RAttributesLayout;
-import com.oracle.truffle.r.runtime.nodes.RBaseNode;
-
-public final class FixedAttributeSetter extends RBaseNode {
-
-    private final String name;
-    private final BranchProfile classProfile = BranchProfile.create();
-    private final BranchProfile dimProfile = BranchProfile.create();
-    private final BranchProfile namesProfile = BranchProfile.create();
-
-    private FixedAttributeSetter(String name) {
-        this.name = name;
-    }
-
-    public static FixedAttributeSetter create(String name) {
-        return new FixedAttributeSetter(name);
-    }
-
-    public static FixedAttributeSetter createNames() {
-        return FixedAttributeSetter.create(RRuntime.NAMES_ATTR_KEY);
-    }
-
-    public static FixedAttributeSetter createDim() {
-        return FixedAttributeSetter.create(RRuntime.DIM_ATTR_KEY);
-    }
-
-    public static FixedAttributeSetter createDimNames() {
-        return FixedAttributeSetter.create(RRuntime.DIMNAMES_ATTR_KEY);
-    }
-
-    public static FixedAttributeSetter createClass() {
-        return FixedAttributeSetter.create(RRuntime.CLASS_ATTR_KEY);
-    }
-
-    // @TruffleBoundary
-    public void execute(DynamicObject attrs, Object value) {
-        if (name == RRuntime.CLASS_ATTR_KEY) {
-            RAttributesLayout.setClass(attrs, value, classProfile);
-        } else if (name == RRuntime.DIM_ATTR_KEY) {
-            RAttributesLayout.setDim(attrs, value, dimProfile);
-        } else if (name == RRuntime.NAMES_ATTR_KEY) {
-            RAttributesLayout.setNames(attrs, value, namesProfile);
-        } else {
-            attrs.define(name, value);
-        }
-    }
-
-}
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
new file mode 100644
index 0000000000..4db056d00d
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetFixedAttributeNode.java
@@ -0,0 +1,72 @@
+/*
+ * 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.object.Location;
+import com.oracle.truffle.api.object.Shape;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout.ConstantShapesAndLocations;
+
+public abstract class GetFixedAttributeNode extends FixedAttributeAccessNode {
+
+    protected GetFixedAttributeNode(String name, Shape[] constantShapes, Location[] constantLocations) {
+        super(name, constantShapes, constantLocations);
+    }
+
+    public static GetFixedAttributeNode create(String name, Shape[] constantShapes, Location[] constantLocations) {
+        return GetFixedAttributeNodeGen.create(name, constantShapes, constantLocations);
+    }
+
+    public static GetFixedAttributeNode create(String name) {
+        ConstantShapesAndLocations csl = RAttributesLayout.getConstantShapesAndLocations(name);
+        return GetFixedAttributeNodeGen.create(name, csl.getConstantShapes(), csl.getConstantLocations());
+    }
+
+    public static GetFixedAttributeNode createNames() {
+        return GetFixedAttributeNode.create(RRuntime.NAMES_ATTR_KEY);
+    }
+
+    public static GetFixedAttributeNode createDim() {
+        return GetFixedAttributeNode.create(RRuntime.DIM_ATTR_KEY);
+    }
+
+    public static GetFixedAttributeNode createClass() {
+        return GetFixedAttributeNode.create(RRuntime.CLASS_ATTR_KEY);
+    }
+
+    public abstract Object execute(DynamicObject attrs);
+
+    @Specialization(limit = "constantShapes.length", guards = {"shapeIndex >= 0", "shapeCheck(attrs, shapeIndex)"})
+    protected Object getFromConstantLocation(DynamicObject attrs, @Cached("findShapeIndex(attrs)") int shapeIndex) {
+        return constantLocations[shapeIndex].get(attrs);
+    }
+
+    @Specialization(contains = "getFromConstantLocation")
+    protected Object getFromObject(DynamicObject attrs, @Cached("create()") GetAttributeNode getter) {
+        return getter.execute(attrs, name);
+    }
+}
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
new file mode 100644
index 0000000000..b803f0f875
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SetFixedAttributeNode.java
@@ -0,0 +1,86 @@
+/*
+ * 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.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.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout;
+import com.oracle.truffle.r.runtime.data.RAttributesLayout.ConstantShapesAndLocations;
+
+public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
+
+    protected SetFixedAttributeNode(String name, Shape[] constantShapes, Location[] constantLocations) {
+        super(name, constantShapes, constantLocations);
+    }
+
+    public static SetFixedAttributeNode create(String name, Shape[] constantShapes, Location[] constantLocations) {
+        return SetFixedAttributeNodeGen.create(name, constantShapes, constantLocations);
+    }
+
+    public static SetFixedAttributeNode create(String name) {
+        ConstantShapesAndLocations csl = RAttributesLayout.getConstantShapesAndLocations(name);
+        return SetFixedAttributeNodeGen.create(name, csl.getConstantShapes(), csl.getConstantLocations());
+    }
+
+    public static SetFixedAttributeNode createNames() {
+        return SetFixedAttributeNode.create(RRuntime.NAMES_ATTR_KEY);
+    }
+
+    public static SetFixedAttributeNode createDim() {
+        return SetFixedAttributeNode.create(RRuntime.DIM_ATTR_KEY);
+    }
+
+    public static SetFixedAttributeNode createDimNames() {
+        return SetFixedAttributeNode.create(RRuntime.DIMNAMES_ATTR_KEY);
+    }
+
+    public static SetFixedAttributeNode createClass() {
+        return SetFixedAttributeNode.create(RRuntime.CLASS_ATTR_KEY);
+    }
+
+    public abstract void execute(DynamicObject attrs, Object value);
+
+    @Specialization(limit = "constantShapes.length", guards = {"shapeIndex >= 0", "shapeCheck(attrs, shapeIndex)"})
+    protected void setFromConstantLocation(DynamicObject attrs, Object value, @Cached("findShapeIndex(attrs)") int shapeIndex) {
+        constantLocations[shapeIndex].get(attrs);
+        try {
+            constantLocations[shapeIndex].set(attrs, value, constantShapes[shapeIndex]);
+        } catch (IncompatibleLocationException | FinalLocationException ex) {
+            RInternalError.reportError(ex);
+        }
+
+    }
+
+    @Specialization(contains = "setFromConstantLocation")
+    protected void setFromObject(DynamicObject attrs, Object value, @Cached("create()") SetAttributeNode setter) {
+        setter.execute(attrs, name, value);
+    }
+
+}
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 5fa502f7fe..c8226e1827 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
@@ -82,9 +82,9 @@ public abstract class UnaryCopyAttributesNode extends RBaseNode {
                     @Cached("createDim()") FixedAttributeRemover removeDim, //
                     @Cached("createDimNames()") FixedAttributeRemover removeDimNames, //
                     @Cached("create()") InitAttributesNode initAttributes, //
-                    @Cached("createNames()") FixedAttributeSetter putNames, //
-                    @Cached("createDim()") FixedAttributeSetter putDim, //
-                    @Cached("createDimNames()") FixedAttributeSetter putDimNames, //
+                    @Cached("createNames()") SetFixedAttributeNode putNames, //
+                    @Cached("createDim()") SetFixedAttributeNode putDim, //
+                    @Cached("createDimNames()") SetFixedAttributeNode putDimNames, //
                     @Cached("createBinaryProfile()") ConditionProfile noDimensions, //
                     @Cached("createBinaryProfile()") ConditionProfile hasNamesSource, //
                     @Cached("createBinaryProfile()") ConditionProfile hasDimNames) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
index 1f77c5266c..e397c96de1 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java
@@ -35,7 +35,7 @@ import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.nodes.RASTUtils;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeGetter;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.UnaryNode;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -63,7 +63,7 @@ public abstract class ClassHierarchyNode extends UnaryNode {
 
     private static final RStringVector truffleObjectClassHeader = RDataFactory.createStringVectorFromScalar("truffle.object");
 
-    @Child private FixedAttributeGetter access;
+    @Child private GetFixedAttributeNode access;
     @Child private S4Class s4Class;
 
     private final boolean withImplicitTypes;
@@ -133,7 +133,7 @@ public abstract class ClassHierarchyNode extends UnaryNode {
         if (noAttributesProfile.profile(attributes != null)) {
             if (access == null) {
                 CompilerDirectives.transferToInterpreterAndInvalidate();
-                access = insert(FixedAttributeGetter.createClass());
+                access = insert(GetFixedAttributeNode.createClass());
             }
             RStringVector classHierarchy = (RStringVector) access.execute(attributes);
             if (nullAttributeProfile.profile(classHierarchy != null)) {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java
index a39df05d0f..d7e65298d2 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java
@@ -27,7 +27,7 @@ import com.oracle.truffle.api.CompilerDirectives;
 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.attributes.FixedAttributeGetter;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -50,7 +50,7 @@ public final class RFactorNodes {
      * Encapsulates the operation of deciding whether a factor is ordered.
      */
     public static final class GetOrdered extends Node {
-        @Child private FixedAttributeGetter isOrderedAccess = FixedAttributeGetter.create(RRuntime.ORDERED_ATTR_KEY);
+        @Child private GetFixedAttributeNode isOrderedAccess = GetFixedAttributeNode.create(RRuntime.ORDERED_ATTR_KEY);
 
         public boolean execute(RAbstractIntVector factor) {
             Object value = isOrderedAccess.execute(factor.getAttributes());
@@ -68,7 +68,7 @@ public final class RFactorNodes {
      */
     public static final class GetLevels extends Node {
         @Child private CastStringNode castString;
-        @Child private FixedAttributeGetter attrAccess = FixedAttributeGetter.create(RRuntime.LEVELS_ATTR_KEY);
+        @Child private GetFixedAttributeNode attrAccess = GetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
 
         private final BranchProfile notVectorBranch = BranchProfile.create();
         private final ConditionProfile nonScalarLevels = ConditionProfile.createBinaryProfile();
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 216a4d9003..9886388b66 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
@@ -17,7 +17,7 @@ import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeGetter;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.FixedAttributeRemover;
 import com.oracle.truffle.r.nodes.unary.CastToVectorNode;
 import com.oracle.truffle.r.nodes.unary.TypeofNode;
@@ -36,11 +36,11 @@ public abstract class GetS4DataSlot extends Node {
 
     public abstract RTypedValue executeObject(RAttributable attObj);
 
-    @Child private FixedAttributeGetter s3ClassAttrAccess;
+    @Child private GetFixedAttributeNode s3ClassAttrAccess;
     @Child private FixedAttributeRemover s3ClassAttrRemove;
     @Child private CastToVectorNode castToVector;
-    @Child private FixedAttributeGetter dotDataAttrAccess;
-    @Child private FixedAttributeGetter dotXDataAttrAccess;
+    @Child private GetFixedAttributeNode dotDataAttrAccess;
+    @Child private GetFixedAttributeNode dotXDataAttrAccess;
     @Child private TypeofNode typeOf = TypeofNodeGen.create();
 
     private final BranchProfile shareable = BranchProfile.create();
@@ -61,7 +61,7 @@ public abstract class GetS4DataSlot extends Node {
             if (attributes != null) {
                 if (s3ClassAttrAccess == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    s3ClassAttrAccess = insert(FixedAttributeGetter.create(RRuntime.DOT_S3_CLASS));
+                    s3ClassAttrAccess = insert(GetFixedAttributeNode.create(RRuntime.DOT_S3_CLASS));
                 }
                 s3Class = s3ClassAttrAccess.execute(attributes);
             }
@@ -95,7 +95,7 @@ public abstract class GetS4DataSlot extends Node {
             if (attributes != null) {
                 if (dotDataAttrAccess == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    dotDataAttrAccess = insert(FixedAttributeGetter.create(RRuntime.DOT_DATA));
+                    dotDataAttrAccess = insert(GetFixedAttributeNode.create(RRuntime.DOT_DATA));
                 }
                 value = dotDataAttrAccess.execute(attributes);
             }
@@ -105,7 +105,7 @@ public abstract class GetS4DataSlot extends Node {
             if (attributes != null) {
                 if (dotXDataAttrAccess == null) {
                     CompilerDirectives.transferToInterpreterAndInvalidate();
-                    dotXDataAttrAccess = insert(FixedAttributeGetter.create(RRuntime.DOT_XDATA));
+                    dotXDataAttrAccess = insert(GetFixedAttributeNode.create(RRuntime.DOT_XDATA));
                 }
                 value = dotXDataAttrAccess.execute(attributes);
             }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
index 0b2585e298..71ae3eef2b 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java
@@ -26,7 +26,7 @@ import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNode;
 import com.oracle.truffle.r.nodes.access.WriteVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode;
 import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
-import com.oracle.truffle.r.nodes.attributes.FixedAttributeGetter;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.function.call.CallRFunctionNode;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RCaller;
@@ -45,10 +45,10 @@ abstract class LoadMethod extends RBaseNode {
 
     public abstract RFunction executeRFunction(VirtualFrame frame, RAttributable fdef, String fname);
 
-    @Child private FixedAttributeGetter targetAttrAccess = FixedAttributeGetter.create(RRuntime.R_TARGET);
-    @Child private FixedAttributeGetter definedAttrAccess = FixedAttributeGetter.create(RRuntime.R_DEFINED);
-    @Child private FixedAttributeGetter nextMethodAttrAccess = FixedAttributeGetter.create(RRuntime.R_NEXT_METHOD);
-    @Child private FixedAttributeGetter sourceAttrAccess = FixedAttributeGetter.create(RRuntime.R_SOURCE);
+    @Child private GetFixedAttributeNode targetAttrAccess = GetFixedAttributeNode.create(RRuntime.R_TARGET);
+    @Child private GetFixedAttributeNode definedAttrAccess = GetFixedAttributeNode.create(RRuntime.R_DEFINED);
+    @Child private GetFixedAttributeNode nextMethodAttrAccess = GetFixedAttributeNode.create(RRuntime.R_NEXT_METHOD);
+    @Child private GetFixedAttributeNode sourceAttrAccess = GetFixedAttributeNode.create(RRuntime.R_SOURCE);
     @Child private WriteLocalFrameVariableNode writeRTarget = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_TARGET, null, WriteVariableNode.Mode.REGULAR);
     @Child private WriteLocalFrameVariableNode writeRDefined = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_DEFINED, null, WriteVariableNode.Mode.REGULAR);
     @Child private WriteLocalFrameVariableNode writeRNextMethod = WriteLocalFrameVariableNode.create(RRuntime.R_DOT_NEXT_METHOD, null, WriteVariableNode.Mode.REGULAR);
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 fa45ec10df..b02d46ea73 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
@@ -15,7 +15,7 @@ package com.oracle.truffle.r.nodes.objects;
 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.FixedAttributeGetter;
+import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastNode;
@@ -35,7 +35,7 @@ public abstract class NewObject extends RExternalBuiltinNode.Arg1 {
     @Child private AccessSlotNode accessSlotClassName = AccessSlotNodeGen.create(true, null, null);
     @Child private AccessSlotNode accessSlotPrototypeName = AccessSlotNodeGen.create(true, null, null);
     @Child private DuplicateNode duplicate = DuplicateNodeGen.create(true);
-    @Child private FixedAttributeGetter pckgAttrAccess = FixedAttributeGetter.create(RRuntime.PCKG_ATTR_KEY);
+    @Child private GetFixedAttributeNode pckgAttrAccess = GetFixedAttributeNode.create(RRuntime.PCKG_ATTR_KEY);
 
     @Child private CastNode castStringScalar;
     @Child private CastNode castLogicalScalar;
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 777cf6b696..7cca08a656 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
@@ -22,98 +22,120 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
-import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import com.oracle.truffle.api.CompilerDirectives.ValueType;
 import com.oracle.truffle.api.object.DynamicObject;
 import com.oracle.truffle.api.object.DynamicObjectFactory;
-import com.oracle.truffle.api.object.FinalLocationException;
-import com.oracle.truffle.api.object.HiddenKey;
-import com.oracle.truffle.api.object.IncompatibleLocationException;
 import com.oracle.truffle.api.object.Layout;
-import com.oracle.truffle.api.object.LocationModifier;
+import com.oracle.truffle.api.object.Location;
 import com.oracle.truffle.api.object.ObjectType;
 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;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 
 public final class RAttributesLayout {
 
-    public static class RAttributesType extends com.oracle.truffle.api.object.ObjectType {
-    }
-
-    private static final RAttributesType RATTR_TYPE = new RAttributesType();
-
-    private static final Layout LAYOUT = Layout.newLayout().build();
-    private static final Shape.Allocator RATTR_ALLOCATOR = LAYOUT.createAllocator();
-
-    private static final HiddenKey COMMON_IDENTIFIER = new HiddenKey("commonProperties");
-    private static final Property COMMON_PROPERTIES = Property.create(COMMON_IDENTIFIER, RATTR_ALLOCATOR.locationForType(Object.class, EnumSet.of(LocationModifier.Final, LocationModifier.NonNull)),
-                    0);
-
-    private static final DynamicObjectFactory RATTR_FACTORY = createAttrFactory();
+    public static class RAttributesType extends ObjectType {
+    }
+
+    private static final AttrsLayout EMPTY_ATTRS_LAYOUT = new AttrsLayout();
+    private static final AttrsLayout CLASS_ATTRS_LAYOUT = new AttrsLayout(RRuntime.CLASS_ATTR_KEY);
+    private static final AttrsLayout NAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY);
+    private static final AttrsLayout DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY);
+    private static final AttrsLayout DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIMNAMES_ATTR_KEY);
+    private static final AttrsLayout NAMES_AND_DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIM_ATTR_KEY);
+    private static final AttrsLayout DIM_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY);
+
+    public static final AttrsLayout[] LAYOUTS = {EMPTY_ATTRS_LAYOUT, CLASS_ATTRS_LAYOUT, NAMES_ATTRS_LAYOUT, DIM_ATTRS_LAYOUT, DIMNAMES_ATTRS_LAYOUT, NAMES_AND_DIM_ATTRS_LAYOUT,
+                    DIM_AND_DIMNAMES_ATTRS_LAYOUT};
+
+    private static final Map<String, ConstantShapesAndLocations> constantShapesAndLocationsForAttribute = new HashMap<>();
+
+    static {
+        constantShapesAndLocationsForAttribute.put(RRuntime.CLASS_ATTR_KEY, new ConstantShapesAndLocations(
+                        new Shape[]{
+                                        CLASS_ATTRS_LAYOUT.shape
+                        },
+                        new Location[]{
+                                        CLASS_ATTRS_LAYOUT.properties[0].getLocation()
+                        }));
+        constantShapesAndLocationsForAttribute.put(RRuntime.NAMES_ATTR_KEY, new ConstantShapesAndLocations(
+                        new Shape[]{
+                                        NAMES_ATTRS_LAYOUT.shape,
+                                        NAMES_AND_DIM_ATTRS_LAYOUT.shape
+                        },
+                        new Location[]{
+                                        NAMES_ATTRS_LAYOUT.properties[0].getLocation(),
+                                        NAMES_AND_DIM_ATTRS_LAYOUT.properties[0].getLocation()
+                        }));
+        constantShapesAndLocationsForAttribute.put(RRuntime.DIM_ATTR_KEY, new ConstantShapesAndLocations(
+                        new Shape[]{
+                                        DIM_ATTRS_LAYOUT.shape,
+                                        NAMES_AND_DIM_ATTRS_LAYOUT.shape,
+                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.shape
+                        },
+                        new Location[]{
+                                        DIM_ATTRS_LAYOUT.properties[0].getLocation(),
+                                        NAMES_AND_DIM_ATTRS_LAYOUT.properties[1].getLocation(),
+                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.properties[0].getLocation()
+                        }));
+        constantShapesAndLocationsForAttribute.put(RRuntime.DIMNAMES_ATTR_KEY, new ConstantShapesAndLocations(
+                        new Shape[]{
+                                        DIMNAMES_ATTRS_LAYOUT.shape,
+                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.shape
+                        },
+                        new Location[]{
+                                        DIMNAMES_ATTRS_LAYOUT.properties[0].getLocation(),
+                                        DIM_AND_DIMNAMES_ATTRS_LAYOUT.properties[1].getLocation()
+                        }));
 
-    private RAttributesLayout() {
     }
 
-    private static DynamicObjectFactory createAttrFactory() {
-        return LAYOUT.createShape(RATTR_TYPE).addProperty(COMMON_PROPERTIES).createFactory();
+    private RAttributesLayout() {
     }
 
     public static DynamicObject createRAttributes() {
-        return RATTR_FACTORY.newInstance(new CommonLocations());
+        return EMPTY_ATTRS_LAYOUT.factory.newInstance();
     }
 
     public static DynamicObject createRAttributes(String[] names, Object[] values) {
         assert names != null && values != null && names.length == values.length;
 
-        DynamicObject attrs = createRAttributes();
-        for (int i = 0; i < names.length; i++) {
-            attrs.define(names[i], values[i]);
-        }
-        return attrs;
+        AttrsLayout attrsLayout = new AttrsLayout(names);
+        return attrsLayout.factory.newInstance(values);
     }
 
     public static DynamicObject createClass(Object cls) {
-        DynamicObject attrs = createRAttributes();
-        attrs.define(RRuntime.CLASS_ATTR_KEY, cls);
-        return attrs;
+        return CLASS_ATTRS_LAYOUT.factory.newInstance(cls);
     }
 
     public static DynamicObject createNames(Object names) {
-        DynamicObject attrs = createRAttributes();
-        attrs.define(RRuntime.NAMES_ATTR_KEY, names);
-        return attrs;
+        return NAMES_ATTRS_LAYOUT.factory.newInstance(names);
     }
 
     public static DynamicObject createDim(Object dim) {
-        DynamicObject attrs = createRAttributes();
-        attrs.define(RRuntime.DIM_ATTR_KEY, dim);
-        return attrs;
+        return DIM_ATTRS_LAYOUT.factory.newInstance(dim);
     }
 
     public static DynamicObject createDimNames(Object dimNames) {
-        DynamicObject attrs = createRAttributes();
-        attrs.define(RRuntime.DIMNAMES_ATTR_KEY, dimNames);
-        return attrs;
+        return DIMNAMES_ATTRS_LAYOUT.factory.newInstance(dimNames);
     }
 
     public static DynamicObject createNamesAndDim(Object names, Object dim) {
-        DynamicObject attrs = createRAttributes();
-        attrs.define(RRuntime.NAMES_ATTR_KEY, names);
-        attrs.define(RRuntime.DIM_ATTR_KEY, dim);
-        return attrs;
+        return NAMES_AND_DIM_ATTRS_LAYOUT.factory.newInstance(names, dim);
     }
 
     public static DynamicObject createDimAndDimNames(Object dim, Object dimNames) {
-        DynamicObject attrs = createRAttributes();
-        attrs.define(RRuntime.DIM_ATTR_KEY, dim);
-        attrs.define(RRuntime.DIMNAMES_ATTR_KEY, dimNames);
-        return attrs;
+        return DIM_AND_DIMNAMES_ATTRS_LAYOUT.factory.newInstance(dim, dimNames);
+    }
+
+    public static ConstantShapesAndLocations getConstantShapesAndLocations(String attrName) {
+        return constantShapesAndLocationsForAttribute.getOrDefault(attrName, ConstantShapesAndLocations.EMPTY);
     }
 
     public static boolean isRAttributes(Object attrs) {
@@ -145,15 +167,15 @@ public final class RAttributesLayout {
     public static List<Property> getPropertyList(DynamicObject attrs, BranchProfile listProfile) {
         assert isRAttributes(attrs);
 
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        return comLoc.getPropertyList(attrs, listProfile);
+        // todo
+        return attrs.getShape().getPropertyList();
     }
 
     public static List<Property> getPropertyList(DynamicObject attrs) {
         assert isRAttributes(attrs);
 
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        return comLoc.getPropertyList(attrs);
+        // todo
+        return attrs.getShape().getPropertyList();
     }
 
     public static Iterable<RAttributesLayout.RAttribute> asIterable(DynamicObject attrs, BranchProfile listProfile) {
@@ -164,6 +186,49 @@ public final class RAttributesLayout {
         return new RAttributeIterableNoProfile(attrs);
     }
 
+    public static final class AttrsLayout {
+        private final Layout layout = Layout.newLayout().build();
+        private final Shape.Allocator allocator = layout.createAllocator();
+        public final Shape shape;
+        public final Property[] properties;
+        public final DynamicObjectFactory factory;
+
+        private AttrsLayout(String... attrNames) {
+            this.properties = new Property[attrNames.length];
+            Shape s = layout.createShape(new RAttributesType());
+            for (int i = 0; i < attrNames.length; i++) {
+                Property p = Property.create(attrNames[i], allocator.locationForType(Object.class), 0);
+                this.properties[i] = p;
+                s = s.addProperty(p);
+            }
+            shape = s;
+            factory = s.createFactory();
+        }
+    }
+
+    public static final class ConstantShapesAndLocations {
+        private static final Shape[] EMPTY_SHAPES_ARRAY = new Shape[0];
+        private static final Location[] EMPTY_LOCATIONS_ARRAY = new Location[0];
+
+        public static final ConstantShapesAndLocations EMPTY = new ConstantShapesAndLocations(EMPTY_SHAPES_ARRAY, EMPTY_LOCATIONS_ARRAY);
+
+        private final Shape[] constantShapes;
+        private final Location[] constantLocations;
+
+        private ConstantShapesAndLocations(Shape[] constantShapes, Location[] constantLocations) {
+            this.constantShapes = constantShapes;
+            this.constantLocations = constantLocations;
+        }
+
+        public Shape[] getConstantShapes() {
+            return constantShapes;
+        }
+
+        public Location[] getConstantLocations() {
+            return constantLocations;
+        }
+    }
+
     static final class RAttributeIterable implements Iterable<RAttributesLayout.RAttribute> {
         private final DynamicObject attrs;
         private final BranchProfile listProfile;
@@ -196,127 +261,6 @@ public final class RAttributesLayout {
 
     }
 
-    public static Object getNames(DynamicObject attrs, BranchProfile attrProfile) {
-        assert isRAttributes(attrs);
-
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        return comLoc.namesLoc.get(attrs, attrProfile);
-    }
-
-    public static void setNames(DynamicObject attrs, Object value, BranchProfile attrProfile) {
-        assert isRAttributes(attrs);
-
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        comLoc.namesLoc.set(attrs, value, attrProfile);
-    }
-
-    public static Object getDim(DynamicObject attrs, BranchProfile attrProfile) {
-        assert isRAttributes(attrs);
-
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        return comLoc.dimLoc.get(attrs, attrProfile);
-    }
-
-    public static void setDim(DynamicObject attrs, Object value, BranchProfile attrProfile) {
-        assert isRAttributes(attrs);
-
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        comLoc.dimLoc.set(attrs, value, attrProfile);
-    }
-
-    public static Object getClass(DynamicObject attrs, BranchProfile attrProfile) {
-        assert isRAttributes(attrs);
-
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        return comLoc.classLoc.get(attrs, attrProfile);
-    }
-
-    public static void setClass(DynamicObject attrs, Object value, BranchProfile attrProfile) {
-        assert isRAttributes(attrs);
-
-        CommonLocations comLoc = (CommonLocations) COMMON_PROPERTIES.get(attrs, attrs.getShape());
-        comLoc.classLoc.set(attrs, value, attrProfile);
-    }
-
-    private static final class CommonLocations {
-
-        private final class CommonLocation {
-            private final String name;
-            private Shape shape;
-            private Property prop;
-
-            CommonLocation(String name) {
-                this.name = name;
-            }
-
-            public Object get(DynamicObject attrs, BranchProfile attrProfile) {
-                Shape curShape = attrs.getShape();
-                if (prop == null || curShape != shape) {
-                    attrProfile.enter();
-                    shape = curShape;
-                    prop = shape.getProperty(name);
-                    if (prop == null) {
-                        return null;
-                    }
-                }
-
-                return prop.get(attrs, shape);
-            }
-
-            public void set(DynamicObject attrs, Object value, BranchProfile attrProfile) {
-                Shape curShape = attrs.getShape();
-
-                if (prop == null || curShape != shape) {
-                    attrProfile.enter();
-                    shape = curShape;
-                    prop = shape.getProperty(name);
-                    if (prop == null) {
-                        attrs.define(name, value);
-                        shape = attrs.getShape();
-                        prop = shape.getProperty(name);
-                        return;
-                    }
-                }
-
-                try {
-                    prop.set(attrs, value, shape);
-                } catch (IncompatibleLocationException | FinalLocationException e) {
-                    throw new UnsupportedOperationException(e);
-                }
-
-            }
-
-        }
-
-        private final CommonLocation namesLoc = new CommonLocation(RRuntime.NAMES_ATTR_KEY);
-        private final CommonLocation dimLoc = new CommonLocation(RRuntime.DIM_ATTR_KEY);
-        private final CommonLocation classLoc = new CommonLocation(RRuntime.CLASS_ATTR_KEY);
-
-        private List<Property> properties;
-        private Shape shapeForProperies;
-
-        CommonLocations() {
-        }
-
-        List<Property> getPropertyList(DynamicObject attrs, BranchProfile listProfile) {
-            if (properties == null || attrs.getShape() != shapeForProperies) {
-                listProfile.enter();
-                properties = attrs.getShape().getPropertyList();
-                shapeForProperies = attrs.getShape();
-            }
-            return properties;
-        }
-
-        List<Property> getPropertyList(DynamicObject attrs) {
-            if (properties == null || attrs.getShape() != shapeForProperies) {
-                properties = attrs.getShape().getPropertyList();
-                shapeForProperies = attrs.getShape();
-            }
-            return properties;
-        }
-
-    }
-
     public interface RAttribute {
         String getName();
 
@@ -324,11 +268,11 @@ public final class RAttributesLayout {
     }
 
     @ValueType
-    static class AttrInstance implements RAttribute {
+    public static final class AttrInstance implements RAttribute {
         private final String name;
         private Object value;
 
-        AttrInstance(String name, Object value) {
+        public AttrInstance(String name, Object value) {
             this.name = name;
             this.value = value;
         }
-- 
GitLab