diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinom.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinom.java
index 8480bde3c0db7647e925bf2254fff2c68d00e5e9..079a0ac5aaa636b00b4fffcc9f0bd6f60947766f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinom.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinom.java
@@ -29,10 +29,10 @@ import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.UpdateSharedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode;
+import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -58,7 +58,7 @@ public abstract class RMultinom extends RExternalBuiltinNode.Arg3 {
                     @Cached("create()") ReuseNonSharedNode reuseNonSharedNode,
                     @Cached("createClassProfile()") ValueProfile randGeneratorClassProfile,
                     @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile,
-                    @Cached("create()") UpdateSharedAttributeNode updateSharedAttributeNode,
+                    @Cached("create()") UpdateShareableChildValueNode updateSharedAttributeNode,
                     @Cached("createNames()") GetFixedAttributeNode getNamesNode,
                     @Cached("createDimNames()") SetFixedAttributeNode setDimNamesNode) {
         RAbstractDoubleVector nonSharedProbs = (RAbstractDoubleVector) reuseNonSharedNode.execute(probsVec);
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 10853a996c8aee8f4c672122aeb90f4cee0f4ebd..c961850f0f7c60e77cd608edd7cac570faa7c58c 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
@@ -40,9 +40,9 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetRowNamesAttributeNode;
-import com.oracle.truffle.r.nodes.attributes.UpdateSharedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -67,7 +67,7 @@ public abstract class Attr extends RBuiltinNode {
 
     @CompilationFinal private String cachedName = "";
     @CompilationFinal private String cachedInternedName = "";
-    @Child private UpdateSharedAttributeNode sharedAttrUpdate = UpdateSharedAttributeNode.create();
+    @Child private UpdateShareableChildValueNode sharedAttrUpdate = UpdateShareableChildValueNode.create();
     @Child private GetAttributeNode attrAccess = GetAttributeNode.create();
     @Child private IterableAttributeNode iterAttrAccess = IterableAttributeNode.create();
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractListElement.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractListElement.java
index 7d5a0921655097e82255396f22c19b04341c69db..5a6b09782203e748ec27868e9d68f7dd2a4c14d6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractListElement.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractListElement.java
@@ -26,19 +26,16 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.profiles.ConditionProfile;
-import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
-import com.oracle.truffle.r.nodes.access.vector.ExtractListElementNodeGen.UpdateStateOfListElementNodeGen;
+import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.runtime.data.RListBase;
-import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 /**
  * Internal node that extracts data under given index from any RAbstractContainer. In the case of
- * RListBase, it also invokes {@link UpdateStateOfListElement} on the element before returning it.
+ * RListBase, it also invokes {@link UpdateShareableChildValueNode} on the element before returning
+ * it.
  *
  * There are two reasons for why one accesses an element of a list: to peek at it, possibly
  * calculate some values from it, and then forget it. In such case, it is OK to access the element
@@ -46,9 +43,9 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
  * {@link RAbstractContainer#getDataAtAsObject(int)}. However, if the object is going to be returned
  * to the user either as return value of a built-in, put inside a list, put as an attribute, or its
  * true reference count matters for some other reason, then its reference count must be put into a
- * consistent state, which is done by {@link UpdateStateOfListElement}. This node is a convenient
- * wrapper that performs the extraction as well as invocation of {@link UpdateStateOfListElement}.
- * See also the documentation of {@link RListBase}.
+ * consistent state, which is done by {@link UpdateShareableChildValueNode}. This node is a
+ * convenient wrapper that performs the extraction as well as invocation of
+ * {@link UpdateShareableChildValueNode}. See also the documentation of {@link RListBase}.
  */
 @TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 public abstract class ExtractListElement extends Node {
@@ -60,7 +57,7 @@ public abstract class ExtractListElement extends Node {
     }
 
     @Specialization
-    protected Object doList(RListBase list, int index, @Cached("create()") UpdateStateOfListElement updateStateNode) {
+    protected Object doList(RListBase list, int index, @Cached("create()") UpdateShareableChildValueNode updateStateNode) {
         Object element = list.getDataAt(index);
         return updateStateNode.updateState(list, element);
     }
@@ -73,61 +70,4 @@ public abstract class ExtractListElement extends Node {
     protected static boolean isNotList(RAbstractContainer x) {
         return !(x instanceof RAbstractListVector);
     }
-
-    @TypeSystemReference(EmptyTypeSystemFlatLayout.class)
-    public abstract static class UpdateStateOfListElement extends Node {
-
-        public abstract void execute(Object owner, Object item);
-
-        /**
-         * Provides more convenient interface for the {@link #execute(Object, Object)} method.
-         */
-        public final <T> T updateState(RAbstractContainer owner, T item) {
-            execute(owner, item);
-            return item;
-        }
-
-        public static UpdateStateOfListElement create() {
-            return UpdateStateOfListElementNodeGen.create();
-        }
-
-        @Specialization
-        protected void doShareableValues(RListBase owner, RShareable value,
-                        @Cached("createClassProfile()") ValueProfile valueProfile,
-                        @Cached("createBinaryProfile()") ConditionProfile sharedValue,
-                        @Cached("createBinaryProfile()") ConditionProfile temporaryOwner) {
-            RShareable profiledValue = valueProfile.profile(value);
-            if (sharedValue.profile(profiledValue.isShared())) {
-                // it is already shared, not need to do anything
-                return;
-            }
-
-            if (temporaryOwner.profile(owner.isTemporary())) {
-                // This can happen, for example, when we immediately extract out of a temporary
-                // list that was returned by a built-in, like: strsplit(...)[[1L]]. We do not need
-                // to transition the element, it may stay temporary.
-                return;
-            }
-
-            if (profiledValue.isTemporary()) {
-                // make it at least non-shared (parent list must be also at least non-shared)
-                profiledValue.incRefCount();
-            }
-            if (owner.isShared()) {
-                // owner is shared, make the value shared too
-                profiledValue.incRefCount();
-            }
-        }
-
-        @Specialization(guards = "isFallback(owner, value)")
-        protected void doFallback(Object owner, Object value) {
-            assert !(value instanceof RShareable && owner instanceof RAbstractVector && !(owner instanceof RListBase)) : "RShareables can only live inside lists and no other vectors.";
-            // nop: either value is not RShareable, or the owner is "list" like structure with
-            // reference semantics (e.g. REnvironment)
-        }
-
-        protected static boolean isFallback(Object owner, Object value) {
-            return !(value instanceof RShareable) || !(owner instanceof RListBase);
-        }
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
index b96380cab8e9f6aa985faee814e5818c88a57986..4b3a19907c7d4ba592ee63ebe20d076e1632b40f 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java
@@ -32,8 +32,8 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
-import com.oracle.truffle.r.nodes.access.vector.ExtractListElement.UpdateStateOfListElement;
 import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
+import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile;
 import com.oracle.truffle.r.nodes.profile.IntValueProfile;
 import com.oracle.truffle.r.nodes.profile.VectorLengthProfile;
@@ -473,14 +473,14 @@ abstract class WriteIndexedVectorNode extends Node {
 
         private final boolean setListElementAsObject;
         private final boolean isReplace;
-        @Child private UpdateStateOfListElement updateStateOfListElement;
+        @Child private UpdateShareableChildValueNode updateStateOfListElement;
         @Child private ShareObjectNode shareObjectNode;
 
         WriteListAction(boolean setListElementAsObject, boolean isReplace) {
             this.setListElementAsObject = setListElementAsObject;
             this.isReplace = isReplace;
             if (!isReplace) {
-                updateStateOfListElement = UpdateStateOfListElement.create();
+                updateStateOfListElement = UpdateShareableChildValueNode.create();
             } else {
                 shareObjectNode = ShareObjectNode.create();
             }
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
index 7671b2971d04890eee553ae87d73d8522131d786..cfe144c94ac383973b0dd0babfa49227070b4415 100644
--- 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
@@ -24,23 +24,33 @@ package com.oracle.truffle.r.nodes.attributes;
 
 import java.util.List;
 
+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.nodes.ExplodeLoop;
 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.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
+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.AttrsLayout;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute;
 
 public abstract class ArrayAttributeNode extends AttributeIterativeAccessNode {
 
+    private static final RAttribute[] EMPTY = new RAttribute[0];
+
+    @Child private ArrayAttributeNode recursive;
+
     public static ArrayAttributeNode create() {
         return ArrayAttributeNodeGen.create();
     }
 
-    public abstract RAttribute[] execute(DynamicObject attrs);
+    public abstract RAttribute[] execute(Object attrs);
 
     @Specialization(limit = "CACHE_LIMIT", guards = {"attrsLayout != null", "attrsLayout.shape.check(attrs)"})
     @ExplodeLoop
@@ -69,7 +79,29 @@ public abstract class ArrayAttributeNode extends AttributeIterativeAccessNode {
         }
 
         return result;
-
     }
 
+    @Specialization
+    protected RAttribute[] getArrayFallback(RAttributable x,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return EMPTY;
+        }
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create());
+        }
+
+        return recursive.execute(attributes);
+    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeAccessNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeAccessNode.java
index d67f5a81d74a009919ed2ad01e5122267b66bc22..5cf678a06dfe84f878b30ad0ca5e27d0b6b35a2e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeAccessNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeAccessNode.java
@@ -23,16 +23,19 @@
 package com.oracle.truffle.r.nodes.attributes;
 
 import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.dsl.TypeSystemReference;
 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.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
  * The base class for the nodes that get/set/remove attributes. It encapsulates the common methods
  * used in guards and for caching.
  */
+@TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 public abstract class AttributeAccessNode extends RBaseNode {
 
     protected AttributeAccessNode() {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeIterativeAccessNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeIterativeAccessNode.java
index a0eee1c48c83079f7a08ce425e143249a7167d50..525c7491fe44c695ec4b011174e7c4b84e092a0e 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeIterativeAccessNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/AttributeIterativeAccessNode.java
@@ -24,11 +24,13 @@ package com.oracle.truffle.r.nodes.attributes;
 
 import com.oracle.truffle.api.CompilerAsserts;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.nodes.ExplodeLoop;
 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.ConditionProfile;
+import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout.AttrsLayout;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
@@ -41,6 +43,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
  * properties (i.e. attributes) it is unnecessary to invoke method {@link Shape#getPropertyList()},
  * which would be more expensive.
  */
+@TypeSystemReference(EmptyTypeSystemFlatLayout.class)
 public abstract class AttributeIterativeAccessNode extends RBaseNode {
 
     protected static final int CACHE_LIMIT = RAttributesLayout.LAYOUTS.length;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java
index 99decfc061953e1c6bc18a7cd0b6d8c317a57870..9032aaefedfbd5b61744a27671cf38dc243df9f7 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/IterableAttributeNode.java
@@ -22,20 +22,28 @@
  */
 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.profiles.BranchProfile;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
+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.AttrsLayout;
 
 public abstract class IterableAttributeNode extends AttributeIterativeAccessNode {
 
+    @Child private IterableAttributeNode recursive;
+
     public static IterableAttributeNode create() {
         return IterableAttributeNodeGen.create();
     }
 
-    public abstract RAttributesLayout.RAttributeIterable execute(DynamicObject attrs);
+    public abstract RAttributesLayout.RAttributeIterable execute(Object attr);
 
     @Specialization(limit = "CACHE_LIMIT", guards = {"attrsLayout != null", "shapeCheck(attrsLayout.shape, attrs)"})
     protected RAttributesLayout.RAttributeIterable getArrayFromConstantLayouts(DynamicObject attrs,
@@ -49,4 +57,27 @@ public abstract class IterableAttributeNode extends AttributeIterativeAccessNode
         return RAttributesLayout.asIterable(attrs);
     }
 
+    @Specialization
+    protected RAttributesLayout.RAttributeIterable getArrayFallback(RAttributable x,
+                    @Cached("create()") BranchProfile attrNullProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+        DynamicObject attributes;
+        if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
+            attributes = ((RAttributeStorage) x).getAttributes();
+        } else {
+            attributes = xTypeProfile.profile(x).getAttributes();
+        }
+
+        if (attributes == null) {
+            attrNullProfile.enter();
+            return RAttributesLayout.RAttributeIterable.EMPTY;
+        }
+        if (recursive == null) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            recursive = insert(create());
+        }
+
+        return recursive.execute(attributes);
+    }
 }
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 aecd9e3c0fc95b1f2f6cdb3c2bb80e3c5ff862da..3b86bb862727a741e13091ce09c2bd026658d5c4 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
@@ -34,6 +34,7 @@ import com.oracle.truffle.api.object.Shape;
 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.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
@@ -148,7 +149,8 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
     protected void setAttrInAttributable(RAttributable x, String name, Object value,
                     @Cached("create()") BranchProfile attrNullProfile,
                     @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                    @Cached("create()") ShareObjectNode updateRefCountNode) {
         DynamicObject attributes;
         if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
             attributes = ((RAttributeStorage) x).getAttributes();
@@ -167,6 +169,11 @@ public abstract class SetAttributeNode extends AttributeAccessNode {
         }
 
         recursive.execute(attributes, name, value);
+
+        // TODO: To verify: It might be beneficial to increment the reference counter only if the
+        // old and new values differ. One should verify, though, whether the costs brought about by
+        // reading the old value do not prevail in the end.
+        updateRefCountNode.execute(value);
     }
 
     /**
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 fd79ede63e6e57041d801f7eecbd7355ca1f50e6..cccbc1cdfc6d8c9e95974478cdbfb17e2cfd7f9c 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
@@ -35,6 +35,7 @@ import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetSpecialAttributeNode;
+import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributeStorage;
@@ -126,7 +127,8 @@ public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
     protected void setAttrInAttributable(RAttributable x, Object value,
                     @Cached("create()") BranchProfile attrNullProfile,
                     @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                    @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                    @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                    @Cached("create()") ShareObjectNode updateRefCountNode) {
         DynamicObject attributes;
         if (attrStorageProfile.profile(x instanceof RAttributeStorage)) {
             attributes = ((RAttributeStorage) x).getAttributes();
@@ -145,6 +147,8 @@ public abstract class SetFixedAttributeNode extends FixedAttributeAccessNode {
         }
 
         recursive.execute(attributes, value);
+
+        updateRefCountNode.execute(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
index e596ca4f5b734b8f433cb47a4b912ab49de67e0a..bc0e2c8a3a6f17199f309e76b7b0f31b9606d8da 100644
--- 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
@@ -31,6 +31,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
 import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.GetDimAttributeNodeGen;
+import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -318,7 +319,8 @@ public final class SpecialAttributesFunctions {
                         @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
                         @Cached("create()") BranchProfile attrNullProfile,
                         @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") ShareObjectNode updateRefCountNode) {
             RVector<?> xProfiled = xTypeProfile.profile(x);
             if (newNames.getLength() > xProfiled.getLength()) {
                 namesTooLongProfile.enter();
@@ -342,7 +344,7 @@ public final class SpecialAttributesFunctions {
                     return;
                 }
 
-                super.setAttrInAttributable(xProfiled, newNames, attrNullProfile, attrStorageProfile, xTypeProfile);
+                super.setAttrInAttributable(xProfiled, newNames, attrNullProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
             }
         }
 
@@ -454,7 +456,8 @@ public final class SpecialAttributesFunctions {
         protected void setOneDimInVector(RVector<?> x, int dim,
                         @Cached("create()") BranchProfile attrNullProfile,
                         @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") ShareObjectNode updateRefCountNode) {
             RAbstractContainer xProfiled = contArgClassProfile.profile(x);
 
             int[] dims = new int[]{dim};
@@ -467,17 +470,19 @@ public final class SpecialAttributesFunctions {
                 attrNullProfile.enter();
                 attrs = RAttributesLayout.createDim(dimVec);
                 xProfiled.initAttributes(attrs);
+                updateRefCountNode.execute(dimVec);
                 return;
             }
 
-            super.setAttrInAttributable(x, dimVec, attrNullProfile, attrStorageProfile, xTypeProfile);
+            super.setAttrInAttributable(x, dimVec, attrNullProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
         }
 
         @Specialization(insertBefore = "setAttrInAttributable")
         protected void setDimsInVector(RVector<?> x, RAbstractIntVector dims,
                         @Cached("create()") BranchProfile attrNullProfile,
                         @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") ShareObjectNode updateRefCountNode) {
             RAbstractContainer xProfiled = contArgClassProfile.profile(x);
             verifyDimensions(xProfiled.getLength(), dims);
 
@@ -486,10 +491,11 @@ public final class SpecialAttributesFunctions {
                 attrNullProfile.enter();
                 attrs = RAttributesLayout.createDim(dims);
                 xProfiled.initAttributes(attrs);
+                updateRefCountNode.execute(dims);
                 return;
             }
 
-            super.setAttrInAttributable(x, dims, attrNullProfile, attrStorageProfile, xTypeProfile);
+            super.setAttrInAttributable(x, dims, attrNullProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
         }
 
         @Specialization(insertBefore = "setAttrInAttributable")
@@ -683,7 +689,8 @@ public final class SpecialAttributesFunctions {
                         @Cached("create()") BranchProfile resizeDimsProfile,
                         @Cached("create()") BranchProfile attrNullProfile,
                         @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") ShareObjectNode updateRefCountNode) {
             int[] dimensions = getDimNode.getDimensions(x);
             if (dimensions == null) {
                 nullDimsProfile.enter();
@@ -727,10 +734,11 @@ public final class SpecialAttributesFunctions {
             if (x.getAttributes() == null) {
                 attrNullProfile.enter();
                 x.initAttributes(RAttributesLayout.createDimNames(resDimNames));
+                updateRefCountNode.execute(resDimNames);
                 return;
             }
 
-            super.setAttrInAttributable(x, resDimNames, attrNullProfile, attrStorageProfile, xTypeProfile);
+            super.setAttrInAttributable(x, resDimNames, attrNullProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
         }
 
         private static boolean isValidDimLength(RStringVector x, int expectedDim) {
@@ -824,13 +832,15 @@ public final class SpecialAttributesFunctions {
         protected void setRowNamesInVector(RVector<?> x, RAbstractVector newRowNames,
                         @Cached("create()") BranchProfile attrNullProfile,
                         @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") ShareObjectNode updateRefCountNode) {
             if (x.getAttributes() == null) {
                 attrNullProfile.enter();
                 x.initAttributes(RAttributesLayout.createRowNames(newRowNames));
+                updateRefCountNode.execute(newRowNames);
                 return;
             }
-            setAttrInAttributable(x, newRowNames, attrNullProfile, attrStorageProfile, xTypeProfile);
+            setAttrInAttributable(x, newRowNames, attrNullProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
         }
 
         @Specialization(insertBefore = "setAttrInAttributable")
@@ -923,8 +933,9 @@ public final class SpecialAttributesFunctions {
                         @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
                         @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile,
                         @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
-            handleVector(vector, null, removeClassAttrNode, initAttrProfile, nullAttrProfile, nullClassProfile, notNullClassProfile, attrStorageProfile, xTypeProfile);
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") ShareObjectNode updateRefCountNode) {
+            handleVector(vector, null, removeClassAttrNode, initAttrProfile, nullAttrProfile, nullClassProfile, notNullClassProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
         }
 
         @Specialization(insertBefore = "setAttrInAttributable")
@@ -935,7 +946,8 @@ public final class SpecialAttributesFunctions {
                         @Cached("createBinaryProfile()") ConditionProfile nullClassProfile,
                         @Cached("createBinaryProfile()") ConditionProfile notNullClassProfile,
                         @Cached("createBinaryProfile()") ConditionProfile attrStorageProfile,
-                        @Cached("createClassProfile()") ValueProfile xTypeProfile) {
+                        @Cached("createClassProfile()") ValueProfile xTypeProfile,
+                        @Cached("create()") ShareObjectNode updateRefCountNode) {
 
             DynamicObject attrs = vector.getAttributes();
             boolean initializeAttrs = initAttrProfile.profile(attrs == null && classAttr != null && classAttr.getLength() != 0);
@@ -943,6 +955,7 @@ public final class SpecialAttributesFunctions {
                 nullAttrProfile.enter();
                 attrs = RAttributesLayout.createClass(classAttr);
                 vector.initAttributes(attrs);
+                updateRefCountNode.execute(classAttr);
             }
             if (nullClassProfile.profile(attrs != null && (classAttr == null || classAttr.getLength() == 0))) {
                 removeAttributeMapping(vector, attrs, removeClassAttrNode);
@@ -953,7 +966,7 @@ public final class SpecialAttributesFunctions {
                         // TODO: Isn't this redundant when the same operation is done after the
                         // loop?
                         if (!initializeAttrs) {
-                            super.setAttrInAttributable(vector, classAttr, nullAttrProfile, attrStorageProfile, xTypeProfile);
+                            super.setAttrInAttributable(vector, classAttr, nullAttrProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
                         }
                         // setClassAttrNode.execute(attrs, classAttr);
                         if (vector.getElementClass() != RInteger.class) {
@@ -971,7 +984,7 @@ public final class SpecialAttributesFunctions {
                 }
 
                 if (!initializeAttrs) {
-                    super.setAttrInAttributable(vector, classAttr, nullAttrProfile, attrStorageProfile, xTypeProfile);
+                    super.setAttrInAttributable(vector, classAttr, nullAttrProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
                 }
             }
         }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/package-info.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9490530d1b5e41a61fddeef56b05ea61df7702d
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/package-info.java
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+/**
+ * <h2>Attributes handling nodes</h2> Generally, this package contains nodes performing basic
+ * operations on attributes, such as setting, getting, removing and iterating. To achieve better
+ * performance, these nodes should be used in preference to the methods on the objects carrying
+ * attributes. In essence, the <code>execute</code> method of each node accepts as its first
+ * argument an object carrying attributes, which may be either an instance of
+ * {@link com.oracle.truffle.api.object.DynamicObject} or
+ * {@link com.oracle.truffle.r.runtime.data.RAttributable} (i.e. lists, vectors etc.).
+ * <p>
+ * <h3>Arbitrary attribute nodes</h3> The nodes in this group operate on the attribute specified as
+ * the second argument of the <code>execute</code> method.
+ * <ul>
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.GetAttributeNode}: retrieves the value of an
+ * arbitrary attribute
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.SetAttributeNode}: sets the value of an
+ * arbitrary attribute. If the first argument is an instance
+ * {@link com.oracle.truffle.r.runtime.data.RAttributable}, the node initializes the object with the
+ * empty attributes.
+ * </ul>
+ *
+ * <h3>Fixed attribute nodes</h3> The nodes in this group operate on the attribute that is specified
+ * during the initialization of a node.
+ * <ul>
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode}: retrieves the value of
+ * the predefined attribute
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.HasFixedAttributeNode}: determines the existence
+ * of the predefined attribute
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode}: sets the value of the
+ * predefined attribute. If the first argument is an instance
+ * {@link com.oracle.truffle.r.runtime.data.RAttributable}, the node initializes the object with the
+ * empty attributes.
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode}: removes the
+ * predefined attribute
+ * </ul>
+ * There are additional subclasses of the above-mentioned nodes handling the special attributes,
+ * such as <code>names</code>, <code>dimnames</code> etc.
+ *
+ * <h3>Special attributes handling</h3> The nodes handling the special attributes are derived from
+ * the fixed attribute nodes described in the previous section. The logic in these special attribute
+ * nodes implements side-effects that take place when a given special attribute is retrieved from,
+ * set to or removed from an instance of {@link com.oracle.truffle.r.runtime.data.RAttributable}.
+ * <p>
+ * N.B. The nodes define additional specializations reflecting the fact that those side-effects are
+ * polymorphic (i.e. they may depend on the particular class). These specializations implement in a
+ * more efficient way the logic of their counterparts in attributable objects (such as
+ * {@link com.oracle.truffle.r.runtime.data.model.RAbstractContainer#setDimNames(com.oracle.truffle.r.runtime.data.RList)}
+ * ).
+ * <p>
+ * The setter nodes are outlined in the following list:
+ * <ul>
+ * <li>
+ * {@link com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode}
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode}
+ * <li>
+ * {@link com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode}
+ * <li>
+ * {@link com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode}
+ * <li>
+ * {@link com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetRowNamesAttributeNode}
+ * </ul>
+ * For each node in the list there is a corresponding "get", "has" and "remove" counterpart.
+ * <p>
+ * When creating a fixed attribute node, one needn't take care of whether the attribute is a special
+ * one or not. The static factory methods defined on the base fixed attribute nodes take care of
+ * that and create the corresponding instance as long as the attribute is a special one. Thus, all
+ * the following initializations produce an instance of
+ * {@link com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode}.
+ *
+ * <pre>
+ * &#64;Child private SetFixedAttributeNode setDimNode = SetFixedAttributeNode.create("dim");
+ * &#64;Child private SetFixedAttributeNode setDimNode = SetFixedAttributeNode.create(RRuntime.DIM_ATTR_KEY);
+ * &#64;Child private SetFixedAttributeNode setDimNode = SetFixedAttributeNode.createDim();
+ * &#64;Child private SetFixedAttributeNode setDimNode = SetDimAttributeNode.create();
+ * </pre>
+ *
+ * Similarly, one does not need to take care of the special attributes when accessing arbitrary
+ * attributes in an attributable instance. As shown in the following snippet, the arbitrary
+ * attribute node recognizes a potential special attribute and handles it appropriately.
+ * <p>
+ * N.B. This mechanism works for instances of
+ * {@link com.oracle.truffle.r.runtime.data.RAttributable} only.
+ *
+ * <pre>
+ * &#64;Child
+ * private SetFixedAttributeNode setAttrNode = SetAttributeNode.create();
+ *
+ * &#64;Specialization
+ * protected Object handleStringVector(RAbstractStringVector v, String attrName, Object attrValue) {
+ *    ...
+ *    setAttrNode.execute(vector, attrName, attrValue);
+ *    ...
+ * }
+ * </pre>
+ *
+ * <h3>Iterative nodes</h3> There are two nodes returning iterable instances. The elements returned
+ * by those objects are instances of
+ * {@link com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute}.
+ * <ul>
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode}
+ * <li>{@link com.oracle.truffle.r.nodes.attributes.IterableAttributeNode}
+ * </ul>
+ * The above-mentioned nodes always return a non-null instance, even if an attributable instance has
+ * no attributes.
+ *
+ * <pre>
+ * &#64;Child private IterableAttributeNode iterAttrAccess = IterableAttributeNode.create();
+ *
+ * &#64;Specialization
+ * protected Object handleStringVector(RAbstractStringVector v) {
+ *    ...
+ *    for (RAttribute a : iterAttrAccess.execute(v)) {
+ *      if ("foo".equals(a.getName())) {
+ *          ...
+ *      }
+ *    }
+ *    ...
+ * }
+ * </pre>
+ *
+ */
+package com.oracle.truffle.r.nodes.attributes;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ShareObjectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ShareObjectNode.java
index de2c9eda806469d95e22a5c8c9962e4cafe612a0..81ac78c1819f2a472380e7e554f8a6eb87eae8db 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ShareObjectNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ShareObjectNode.java
@@ -30,8 +30,10 @@ import com.oracle.truffle.api.dsl.TypeSystemReference;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.NodeInfo;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.api.profiles.ValueProfile;
 import com.oracle.truffle.r.nodes.EmptyTypeSystemFlatLayout;
 import com.oracle.truffle.r.runtime.data.RShareable;
+import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage;
 
 /**
  * Internal node that should be used whenever you need to increment reference count of some object.
@@ -48,7 +50,7 @@ public abstract class ShareObjectNode extends Node {
     }
 
     @Specialization
-    protected Object doShareable(RShareable obj,
+    protected Object doShareable(RSharingAttributeStorage obj,
                     @Cached("createBinaryProfile()") ConditionProfile sharedPermanent) {
         if (sharedPermanent.profile(!obj.isSharedPermanent())) {
             obj.incRefCount();
@@ -56,6 +58,17 @@ public abstract class ShareObjectNode extends Node {
         return obj;
     }
 
+    @Specialization
+    protected Object doShareable(RShareable obj,
+                    @Cached("createBinaryProfile()") ConditionProfile sharedPermanent,
+                    @Cached("createClassProfile()") ValueProfile typeProfile) {
+        RShareable objProfiled = typeProfile.profile(obj);
+        if (sharedPermanent.profile(!objProfiled.isSharedPermanent())) {
+            objProfiled.incRefCount();
+        }
+        return obj;
+    }
+
     @Specialization(guards = "!isRShareable(obj)")
     protected Object doNonShareable(Object obj) {
         return obj;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UpdateSharedAttributeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/UpdateShareableChildValueNode.java
similarity index 64%
rename from com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UpdateSharedAttributeNode.java
rename to com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/UpdateShareableChildValueNode.java
index 58bbb082347854e069fd6c8b633021fabf357dc5..5a5a903247df6a7bc4e65da814296a21479f43e4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/UpdateSharedAttributeNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/UpdateShareableChildValueNode.java
@@ -20,18 +20,19 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.nodes.attributes;
+package com.oracle.truffle.r.nodes.function.opt;
 
 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.api.profiles.ValueProfile;
 import com.oracle.truffle.r.runtime.data.RShareable;
+import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
-public abstract class UpdateSharedAttributeNode extends RBaseNode {
+public abstract class UpdateShareableChildValueNode extends RBaseNode {
 
-    protected UpdateSharedAttributeNode() {
+    protected UpdateShareableChildValueNode() {
     }
 
     public abstract void execute(Object owner, Object attrValue);
@@ -41,13 +42,15 @@ public abstract class UpdateSharedAttributeNode extends RBaseNode {
         return item;
     }
 
-    public static UpdateSharedAttributeNode create() {
-        return UpdateSharedAttributeNodeGen.create();
+    public static UpdateShareableChildValueNode create() {
+        return UpdateShareableChildValueNodeGen.create();
     }
 
     @Specialization
     protected void doShareableValues(RShareable owner, RShareable value,
                     @Cached("createClassProfile()") ValueProfile valueProfile,
+                    @Cached("createBinaryProfile()") ConditionProfile sharingAttrsStorageOwner,
+                    @Cached("createClassProfile()") ValueProfile ownerProfile,
                     @Cached("createBinaryProfile()") ConditionProfile sharedValue,
                     @Cached("createBinaryProfile()") ConditionProfile temporaryOwner) {
         RShareable profiledValue = valueProfile.profile(value);
@@ -56,17 +59,34 @@ public abstract class UpdateSharedAttributeNode extends RBaseNode {
             return;
         }
 
+        if (sharingAttrsStorageOwner.profile(owner instanceof RSharingAttributeStorage)) {
+            // monomorphic invocations of the owner
+            RSharingAttributeStorage shOwner = (RSharingAttributeStorage) owner;
+            incRef(shOwner, profiledValue, temporaryOwner);
+        } else {
+            // invoking a type-profiled owner
+            RShareable ownerProfiled = ownerProfile.profile(owner);
+            incRef(ownerProfiled, profiledValue, temporaryOwner);
+        }
+    }
+
+    private static void incRef(RShareable owner, RShareable value, ConditionProfile temporaryOwner) {
         if (temporaryOwner.profile(owner.isTemporary())) {
+            // This can happen, for example, when we immediately extract out of a temporary
+            // list that was returned by a built-in, like: strsplit(...)[[1L]]. We do not need
+            // to transition the element, it may stay temporary.
             return;
         }
 
-        if (profiledValue.isTemporary()) {
+        // the owner is at least non-shared
+
+        if (value.isTemporary()) {
             // make it at least non-shared (the owner must be also at least non-shared)
-            profiledValue.incRefCount();
+            value.incRefCount();
         }
         if (owner.isShared()) {
             // owner is shared, make the attribute value shared too
-            profiledValue.incRefCount();
+            value.incRefCount();
         }
     }
 
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 8f35974969087a286e79230a3b7af3788e483ff2..523100966ba101fd359421ba7c15423cbd3684e2 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,6 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -257,6 +258,9 @@ public final class RAttributesLayout {
     }
 
     public static final class RAttributeIterable implements Iterable<RAttributesLayout.RAttribute> {
+
+        public static final RAttributeIterable EMPTY = new RAttributeIterable(null, null);
+
         private final DynamicObject attrs;
         private final List<Property> properties;
 
@@ -267,7 +271,11 @@ public final class RAttributesLayout {
 
         @Override
         public Iterator<RAttributesLayout.RAttribute> iterator() {
-            return new Iter(attrs, properties.iterator());
+            if (attrs == null || properties == null) {
+                return Collections.emptyIterator();
+            } else {
+                return new Iter(attrs, properties.iterator());
+            }
         }
 
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index b7d3de3e8cfa5e068c4c8de8bfb49016f1be01f6..71f1784301243b7a76d79cad999efb22a031ffe7 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -8309,6 +8309,16 @@ Error in attr(x, 42) <- NULL : 'name' must be non-null character string
 #x<-42; attr(x, NULL) <- NULL
 Error in attr(x, NULL) <- NULL : 'name' must be non-null character string
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_attrassign.testRefCount#
+#x <- c(1,2); attr(x, "foo") <- c("a","b"); y <- x; attr(x,"foo")[[1]] <- "c"; y
+[1] 1 2
+attr(,"foo")
+[1] "a" "b"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_attrassign.testRefCount#
+#x <- c(1,2,3); y <- 42; attr(y, 'at') <- x; x[[1]] <- 2; attr(y, 'at')
+[1] 1 2 3
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_attrassign.testattrassign1#
 #argv <- list(structure(1, foo = structure(list(a = 'a'), .Names = 'a')), 'foo', value = structure(list(a = 'a'), .Names = 'a'));`attr<-`(argv[[1]],argv[[2]],argv[[3]]);
 [1] 1
@@ -27555,6 +27565,12 @@ $z
 [1] 42
 
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testRefCount#
+#{ l <- list(a=c(1,2)); l2 <- l; l$a[[1]] <- 3; l2 }
+$a
+[1] 1 2
+
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testlist1#
 #argv <- list(surname = structure(c('McNeil', 'Ripley', 'Ripley', 'Tierney', 'Tukey', 'Venables', 'R Core'), class = 'AsIs'), nationality = structure(c('Australia', 'UK', 'UK', 'US', 'US', 'Australia', NA), class = 'AsIs'), deceased = structure(c('no', 'no', 'no', 'no', 'yes', 'no', NA), class = 'AsIs'), title = structure(c('Interactive Data Analysis', 'Spatial Statistics', 'Stochastic Simulation', 'LISP-STAT', 'Exploratory Data Analysis', 'Modern Applied Statistics ...', 'An Introduction to R'), class = 'AsIs'), other.author = structure(c(NA, NA, NA, NA, NA, 'Ripley', 'Venables & Smith'), class = 'AsIs'));list(argv[[1]],argv[[2]],argv[[3]],argv[[4]],argv[[5]]);
 [[1]]
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attrassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attrassign.java
index b8b553bad99c00077d46ab1bd2902978b4fab2f2..ab83f538b284c7c7cf469045ea726e1c386b427e 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attrassign.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attrassign.java
@@ -98,6 +98,12 @@ public class TestBuiltin_attrassign extends TestBase {
         assertEval("argv <- list(structure(c(0, -187, -34, 0, 165, 0, -95, 121, 107, 0, 41, 0, 0, 93, 0), .Dim = c(5L, 3L)), 'dimnames', value = NULL);`attr<-`(argv[[1]],argv[[2]],argv[[3]]);");
     }
 
+    @Test
+    public void testRefCount() {
+        assertEval("x <- c(1,2); attr(x, \"foo\") <- c(\"a\",\"b\"); y <- x; attr(x,\"foo\")[[1]] <- \"c\"; y");
+        assertEval("x <- c(1,2,3); y <- 42; attr(y, 'at') <- x; x[[1]] <- 2; attr(y, 'at')");
+    }
+
     @Test
     public void testArgsCasts() {
         assertEval(Output.IgnoreErrorContext, "x<-42; attr(x, NULL) <- NULL");
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
index 0317997c24916e2917819c231054d6cd5b44a61a..e612304d8f81c89851fe5e590a4f2646a6b5b891 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java
@@ -347,6 +347,11 @@ public class TestBuiltin_list extends TestBase {
                         "argv <- list(ANY = structure(function (x, y = NULL) .Internal(crossprod(x, y)), target = structure('ANY', class = structure('signature', package = 'methods'), .Names = 'x', package = 'methods'), defined = structure('ANY', class = structure('signature', package = 'methods'), .Names = 'x', package = 'methods'), generic = structure('crossprod', package = 'base'), class = structure('derivedDefaultMethod', package = 'methods')));list(argv[[1]]);");
     }
 
+    @Test
+    public void testRefCount() {
+        assertEval("{ l <- list(a=c(1,2)); l2 <- l; l$a[[1]] <- 3; l2 }");
+    }
+
     @Test
     public void testList() {
         assertEval("{ list(a=1, b=2) }");