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 e566319c45e2295d220748faa4ca7016294921d1..4583b8b627e416c709b28409b616ce47fae9a7dc 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
@@ -48,12 +48,10 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 @RBuiltin(name = "attr", kind = PRIMITIVE, parameterNames = {"x", "which", "exact"}, behavior = PURE)
 public abstract class Attr extends RBuiltinNode {
@@ -147,9 +145,13 @@ public abstract class Attr extends RBuiltinNode {
         if (a == RNull.instance) {
             return RNull.instance;
         } else {
-            RAbstractVector rowNames = (RAbstractVector) a;
-            return rowNames.getElementClass() == RInteger.class && rowNames.getLength() == 2 && RRuntime.isNA(((RAbstractIntVector) rowNames).getDataAt(0)) ? RDataFactory.createIntSequence(1, 1,
-                            Math.abs(((RAbstractIntVector) rowNames).getDataAt(1))) : a;
+            if (a instanceof RAbstractIntVector) {
+                RAbstractIntVector rowNames = (RAbstractIntVector) a;
+                if (rowNames.getLength() == 2 && RRuntime.isNA(rowNames.getDataAt(0))) {
+                    return RDataFactory.createIntSequence(1, 1, Math.abs(rowNames.getDataAt(1)));
+                }
+            }
+            return a;
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
index 05b94d6661029d7ec72086c0e70947281c0fc4be..1ef9642089f368e94b9a892f92e93e243e0c4e07 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java
@@ -21,7 +21,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.nodes.builtin.CastBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.printer.AnyVectorToStringVectorWriter;
 import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinterNode;
@@ -31,7 +30,6 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -119,7 +117,7 @@ public abstract class Format extends RBuiltinNode {
         assert sciVec.getLength() > 0;
         int tmp = castInteger(sciVec).getDataAt(0);
         int ret;
-        if (sciVec.getElementClass() == RLogical.class) {
+        if (sciVec instanceof RAbstractLogicalVector) {
             if (RRuntime.isNA(tmp)) {
                 ret = tmp;
             } else {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
index 11e4b0d23b6d4415bfb1bf1dad3fbb40f00dd504..e8ba5a9eedebba1267773dc1350c76ac708562d3 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java
@@ -34,7 +34,6 @@ import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
@@ -59,6 +58,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NAProfile;
 
 /*
@@ -158,7 +158,7 @@ public abstract class Match extends RBuiltinNode {
         throw error(MATCH_VECTOR_ARGS);
     }
 
-    protected abstract static class MatchInternalNode extends Node {
+    protected abstract static class MatchInternalNode extends RBaseNode {
 
         private static final int TABLE_SIZE_FACTOR = 10;
 
@@ -467,7 +467,7 @@ public abstract class Match extends RBuiltinNode {
             return RDataFactory.createIntVector(result, setCompleteState(matchAll, nomatch));
         }
 
-        @Specialization(guards = "!isStringVectorTable(table)")
+        @Specialization(guards = "!isRAbstractStringVector(table)")
         protected RIntVector match(RAbstractStringVector x, RAbstractVector table, int nomatch) {
             int[] result = initResult(x.getLength(), nomatch);
             boolean matchAll = true;
@@ -523,10 +523,6 @@ public abstract class Match extends RBuiltinNode {
             return RDataFactory.createIntVector(result, setCompleteState(matchAll, nomatch));
         }
 
-        protected boolean isStringVectorTable(RAbstractVector table) {
-            return table.getElementClass() == String.class;
-        }
-
         private static int[] initResult(int length, int nomatch) {
             int[] result = new int[length];
             Arrays.fill(result, nomatch);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
index 9bd7d7eff312a1e3f0e7a20f2c7f9e41206e5efd..dcc06718fd7c413a679d4fa9a2d7749137c7d8c7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java
@@ -44,16 +44,10 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.conn.RConnection;
 import com.oracle.truffle.r.runtime.conn.StdConnections;
-import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RList;
-import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -506,53 +500,45 @@ public abstract class Scan extends RBuiltinNode {
     }
 
     private static Object extractItem(RAbstractVector what, String buffer, LocalData data) {
-        if (what.getElementClass() == RLogical.class) {
-            if (isNaString(buffer, 0, data)) {
-                return RRuntime.LOGICAL_NA;
-            } else {
-                return RRuntime.string2logicalNoCheck(buffer);
-            }
-        }
-        if (what.getElementClass() == RInteger.class) {
-            if (isNaString(buffer, 0, data)) {
-                return RRuntime.INT_NA;
-            } else {
-                return RRuntime.string2intNoCheck(buffer);
-            }
-        }
-
-        if (what.getElementClass() == RDouble.class) {
-            if (isNaString(buffer, 0, data)) {
-                return RRuntime.DOUBLE_NA;
-            } else {
-                return RRuntime.string2doubleNoCheck(buffer);
-            }
-        }
-
-        if (what.getElementClass() == RComplex.class) {
-            if (isNaString(buffer, 0, data)) {
-                return RRuntime.createComplexNA();
-            } else {
-                return RRuntime.string2complexNoCheck(buffer);
-            }
-        }
-
-        if (what.getElementClass() == RString.class) {
-            if (isNaString(buffer, 1, data)) {
-                return RRuntime.STRING_NA;
-            } else {
-                return buffer;
-            }
-        }
-
-        if (what.getElementClass() == RRaw.class) {
-            if (isNaString(buffer, 0, data)) {
-                return RDataFactory.createRaw((byte) 0);
-            } else {
-                return RRuntime.string2raw(buffer);
-            }
+        switch (what.getRType()) {
+            case Logical:
+                if (isNaString(buffer, 0, data)) {
+                    return RRuntime.LOGICAL_NA;
+                } else {
+                    return RRuntime.string2logicalNoCheck(buffer);
+                }
+            case Integer:
+                if (isNaString(buffer, 0, data)) {
+                    return RRuntime.INT_NA;
+                } else {
+                    return RRuntime.string2intNoCheck(buffer);
+                }
+            case Double:
+                if (isNaString(buffer, 0, data)) {
+                    return RRuntime.DOUBLE_NA;
+                } else {
+                    return RRuntime.string2doubleNoCheck(buffer);
+                }
+            case Complex:
+                if (isNaString(buffer, 0, data)) {
+                    return RRuntime.createComplexNA();
+                } else {
+                    return RRuntime.string2complexNoCheck(buffer);
+                }
+            case Character:
+                if (isNaString(buffer, 1, data)) {
+                    return RRuntime.STRING_NA;
+                } else {
+                    return buffer;
+                }
+            case Raw:
+                if (isNaString(buffer, 0, data)) {
+                    return RDataFactory.createRaw((byte) 0);
+                } else {
+                    return RRuntime.string2raw(buffer);
+                }
+            default:
+                throw RInternalError.shouldNotReachHere();
         }
-
-        throw RInternalError.shouldNotReachHere();
     }
 }
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 867c09bfd9d94bd70f5967e5081c10ab2e3c58cd..c59b1b8d5461f74cc574afd2fd27c6d8d6001681 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
@@ -56,7 +56,7 @@ public abstract class UpdateDim extends RBuiltinNode {
 
     @Specialization
     protected RAbstractVector updateDim(RAbstractVector vector, @SuppressWarnings("unused") RNull dimensions) {
-        RVector<?> result = ((RAbstractVector) reuse.execute(vector)).materialize();
+        RVector<?> result = reuse.execute(vector);
         result.resetDimensions(null);
         return result;
     }
@@ -69,7 +69,7 @@ public abstract class UpdateDim extends RBuiltinNode {
         RIntVector dimensionsMaterialized = dimensions.materialize();
         int[] dimsData = dimensionsMaterialized.getDataCopy();
         RVector.verifyDimensions(vector.getLength(), dimsData, this);
-        RVector<?> result = ((RAbstractVector) reuse.execute(vector)).materialize();
+        RVector<?> result = reuse.execute(vector);
         removeNames.execute(result);
 
         DynamicObject attrs = result.getAttributes();
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
index 0ba6831d05d0ce923b21cda2912c773c0c5c3679..c0286bb86099fbf9de5d3cb8a24c2b204c219c28 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java
@@ -36,7 +36,6 @@ import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
@@ -52,7 +51,7 @@ public abstract class UpdateOldClass extends RBuiltinNode {
         Casts.noCasts(UpdateOldClass.class);
     }
 
-    @Specialization(guards = "!isStringVector(className)")
+    @Specialization(guards = "!isRAbstractStringVector(className)")
     protected Object setOldClass(RAbstractContainer arg, RAbstractVector className) {
         if (className.getLength() == 0) {
             return setOldClass(arg, RNull.instance);
@@ -90,8 +89,4 @@ public abstract class UpdateOldClass extends RBuiltinNode {
         setClassAttributeNode.reset(result);
         return result;
     }
-
-    protected boolean isStringVector(RAbstractVector className) {
-        return className.getElementClass() == RString.class;
-    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
index c986eecf12694fb6ff66f2febf017262bae6aa70..21a620a4a83867c83174a8a1faeb7ce862b4d56e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSubstr.java
@@ -22,8 +22,8 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -75,15 +74,18 @@ public abstract class UpdateSubstr extends RBuiltinNode {
         int actualStop = stop;
         if (!rangeOk(x, start, stop)) {
             everSeenIllegalRange.enter();
-            if (start > stop || (start <= 0 && stop <= 0) || (start > x.length() && stop > x.length())) {
+            if (start > x.length()) {
                 return x;
             }
-            if (start <= 0) {
+            if (start < 1) {
                 actualStart = 1;
             }
-            if (stop > x.length()) {
+            if (stop > x.length() || stop < 0) {
                 actualStop = x.length();
             }
+            if (actualStart > actualStop) {
+                return x;
+            }
         }
         int replacementLength = actualStop - (actualStart - 1);
         if (replacementLength > value.length()) {
@@ -116,30 +118,26 @@ public abstract class UpdateSubstr extends RBuiltinNode {
     }
 
     @SuppressWarnings("unused")
-    @Specialization(guards = {"!emptyArg(arg)", "!wrongParams(start, stop)", "wrongValue(value)"})
+    @Specialization(guards = {"!emptyArg(arg)", "!wrongParams(start, stop)", "!isRAbstractStringVector(value) || value.getLength() == 0"})
     protected RStringVector substr(RAbstractStringVector arg, RAbstractIntVector start, RAbstractIntVector stop, RAbstractVector value) {
         CompilerDirectives.transferToInterpreter();
         throw error(RError.Message.INVALID_UNNAMED_VALUE);
     }
 
-    @Specialization(guards = {"!emptyArg(arg)", "!wrongParams(start, stop)", "!wrongValue(value)"})
+    @Specialization(guards = {"!emptyArg(arg)", "!wrongParams(start, stop)", "value.getLength() > 0"})
     @TruffleBoundary
     protected RStringVector substr(RAbstractStringVector arg, RAbstractIntVector start, RAbstractIntVector stop, RAbstractStringVector value) {
-        int argLength = arg.getLength();
-        String[] res = new String[argLength];
+        String[] res = new String[arg.getLength()];
         na.enable(arg);
         na.enable(start);
         na.enable(stop);
         int startLength = start.getLength();
         int stopLength = stop.getLength();
         int valueLength = value.getLength();
-        int j;
-        int k;
-        int l;
-        for (int i = 0; i < argLength; i++) {
-            j = i % startLength;
-            k = i % stopLength;
-            l = i % valueLength;
+        for (int i = 0; i < res.length; i++) {
+            int j = i % startLength;
+            int k = i % stopLength;
+            int l = i % valueLength;
             res[i] = substr0(arg.getDataAt(i), start.getDataAt(j), stop.getDataAt(k), value.getDataAt(l));
         }
         return RDataFactory.createStringVector(res, na.neverSeenNA());
@@ -156,8 +154,4 @@ public abstract class UpdateSubstr extends RBuiltinNode {
         }
         return false;
     }
-
-    protected boolean wrongValue(RAbstractVector value) {
-        return value.getElementClass() != RString.class || value.getLength() == 0;
-    }
 }
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 0282196c311a23fda95119e1a469bde3e2c88cf5..f1212c7fd39570abe91325adcfc70f9dab72d7a9 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
@@ -514,11 +514,6 @@ public final class ValuePrinterNode extends RBaseNode {
             throw RInternalError.shouldNotReachHere();
         }
 
-        @Override
-        public Class<?> getElementClass() {
-            throw RInternalError.shouldNotReachHere();
-        }
-
         @Override
         public RTypedValue getNonShared() {
             throw RInternalError.shouldNotReachHere();
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 cab5bc6f2b66519d3a4c37a4bfc6d38d30f4342b..0cdf97146b9f4b8f451e1486d52ff9028dc02321 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
@@ -41,7 +41,6 @@ import com.oracle.truffle.r.runtime.data.RAttributable;
 import com.oracle.truffle.r.runtime.data.RAttributesLayout;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RInteger;
 import com.oracle.truffle.r.runtime.data.RLanguage;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
@@ -1063,20 +1062,8 @@ public final class SpecialAttributesFunctions {
                 for (int i = 0; i < classAttr.getLength(); i++) {
                     String attr = classAttr.getDataAt(i);
                     if (RRuntime.CLASS_FACTOR.equals(attr)) {
-                        // TODO: Isn't this redundant when the same operation is done after the
-                        // loop?
-                        if (!initializeAttrs) {
-                            super.setAttrInAttributable(vector, classAttr, nullAttrProfile, attrStorageProfile, xTypeProfile, updateRefCountNode);
-                        }
-                        if (vector.getElementClass() != RInteger.class) {
-                            // N.B. there used to be conversion to integer under certain
-                            // circumstances.
-                            // However, it seems that it was dead/obsolete code so it was removed.
-                            // Notes: this can only happen if the class is set by hand to some
-                            // non-integral vector, i.e. attr(doubles, 'class') <- 'factor'. GnuR
-                            // also
-                            // does not update the 'class' attr with other, possibly
-                            // valid classes when it reaches this error.
+                        if (!(vector instanceof RAbstractIntVector)) {
+                            CompilerDirectives.transferToInterpreter();
                             throw error(RError.Message.ADDING_INVALID_CLASS, "factor");
                         }
                     }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java
index d1166630d436d8e5685c376d8243c0369f15878f..09ef7a3fc56c1c0f0474bb0b4947012ffbb12f00 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/opt/ReuseNonSharedNode.java
@@ -22,47 +22,74 @@
  */
 package com.oracle.truffle.r.nodes.function.opt;
 
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.runtime.data.RShareable;
 import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage;
+import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 
 /**
  * Internal node that should be used whenever you want to alter some data: if the data is shared,
  * then it creates a copy, otherwise it returns the data. It does not increment the reference count
  * of the result in either case, but that is typically handled by write variable node, put container
  * element node or by put attribute node.
+ *
+ * This node also makes sure that the returned value is an actual RVector in which individual
+ * elements can be modified (as opposed to sequences, etc.) by calling materialize.
  */
 public abstract class ReuseNonSharedNode extends Node {
 
+    protected static final int LIMIT = 5;
+
     public static ReuseNonSharedNode create() {
         return ReuseNonSharedNodeGen.create();
     }
 
-    public abstract Object execute(Object value);
-
-    @Specialization(guards = "!value.isShared()")
-    protected RShareable reuseNonShared(RSharingAttributeStorage value) {
-        return value;
-    }
-
-    @Specialization(guards = {"value.isShared()", "value.getClass() == valueClass"})
-    protected RSharingAttributeStorage reuseShared(RSharingAttributeStorage value,
-                    @Cached("value.getClass()") Class<? extends RSharingAttributeStorage> valueClass) {
-        RSharingAttributeStorage res = valueClass.cast(value).copy();
-        assert res.isTemporary();
-        return res;
-    }
+    public abstract RVector<?> execute(RAbstractVector value);
 
-    protected static boolean isRShareable(Object value) {
-        return value instanceof RSharingAttributeStorage;
+    @Specialization(limit = "LIMIT", guards = "value.getClass() == valueClass")
+    protected RVector<?> reuseNonShareable(RAbstractVector value,
+                    @Cached("value.getClass()") Class<? extends RAbstractVector> valueClass,
+                    @Cached("createBinaryProfile()") ConditionProfile isSharedProfile) {
+        RAbstractVector profiledValue = valueClass.cast(value);
+        if (RShareable.class.isAssignableFrom(valueClass)) {
+            RShareable shareable = (RShareable) profiledValue;
+            if (isSharedProfile.profile(shareable.isShared())) {
+                RShareable res = shareable.copy();
+                assert res.isTemporary();
+                return (RVector<?>) res;
+            } else {
+                return (RVector<?>) profiledValue;
+            }
+        } else {
+            RVector<?> res = profiledValue.materialize();
+            assert res.isTemporary();
+            return res;
+        }
     }
 
     @Fallback
-    protected static Object getNonShareable(Object value) {
+    @TruffleBoundary
+    public static RVector<?> reuseSlow(RAbstractVector value) {
         RSharingAttributeStorage.verify(value);
-        return value;
+        if (value instanceof RSharingAttributeStorage) {
+            RShareable shareable = (RShareable) value;
+            if (shareable.isShared()) {
+                RShareable res = shareable.copy();
+                assert res.isTemporary();
+                return (RVector<?>) res;
+            } else {
+                return (RVector<?>) value;
+            }
+        } else {
+            RVector<?> res = value.materialize();
+            assert res.isTemporary();
+            return res;
+        }
     }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 38f80bcd6a4e9651ff0e4135b632380de2cc7a48..ae1752dba77dd30918961e82469210de382d186e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -865,6 +865,7 @@ public final class RError extends RuntimeException {
         SYMBOL_HAS_REGULAR_BINDING("symbol already has a regular binding"),
         CANNOT_CHANGE_LOCKED_ACTIVE_BINDING("cannot change active binding if binding is locked"),
         NO_BINDING_FOR("no binding for \"%s\""),
+        INVALID_SUBSTRING_ARGS("invalid substring arguments"),
         REPLACING_IN_NON_CHAR_OBJ("replacing substrings in a non-character object");
 
         public final String message;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
index a4eb4d6a405792e737c2bf1b69462518880b5fe8..d58525dcf8b4339129f7dd66efb9d7686c6136ca 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java
@@ -159,11 +159,6 @@ public class RLanguage extends RSharingAttributeStorage implements RAbstractCont
         throw RInternalError.unimplemented();
     }
 
-    @Override
-    public Class<?> getElementClass() {
-        return RLanguage.class;
-    }
-
     @Override
     public RLanguage materialize() {
         // TODO is copy necessary?
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
index 537d54d73051c4026054cb467d2661f4b271bf06..b4abaf3bbeda5b5bf2c241a85157ecd2014d9abf 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, 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
@@ -139,11 +139,6 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
         data[toIndex] = other.getDataAtAsObject(fromIndex);
     }
 
-    @Override
-    public final Class<?> getElementClass() {
-        return Object.class;
-    }
-
     @TruffleBoundary
     public final Object getNameAt(int index) {
         RStringVector names = getNamesFromAttrs();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
index 32d4e8881858f429fa8a630ce55be34b9f4e4001..35f18166cbf45897b115199f6c6f0953468cf3ce 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java
@@ -261,11 +261,6 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra
         throw RInternalError.shouldNotReachHere();
     }
 
-    @Override
-    public Class<?> getElementClass() {
-        return null;
-    }
-
     @Override
     public RSharingAttributeStorage copy() {
         RPairList result = new RPairList();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index e0d3de69805cc1ae9818feff2efeba042e25f70e..0b84bc51a2d20226b48872ed7d9d11e81f9fded5 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -513,14 +513,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
             for (int i = 0; i < classAttr.getLength(); i++) {
                 String attr = classAttr.getDataAt(i);
                 if (RRuntime.CLASS_FACTOR.equals(attr)) {
-                    vector.putAttribute(RRuntime.CLASS_ATTR_KEY, classAttr);
-                    if (vector.getElementClass() != RInteger.class) {
-                        // N.B. there used to be conversion to integer under certain circumstances.
-                        // However, it seems that it was dead/obsolete code so it was removed.
-                        // Notes: this can only happen if the class is set by hand to some
-                        // non-integral vector, i.e. attr(doubles, 'class') <- 'factor'. GnuR also
-                        // does not update the 'class' attr with other, possibly
-                        // valid classes when it reaches this error.
+                    if (!(vector instanceof RAbstractIntVector)) {
                         throw RError.error(RError.SHOW_CALLER2, RError.Message.ADDING_INVALID_CLASS, "factor");
                     }
                 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java
index 8260e9b21a901e441fd281c74e7624324865bd01..d16147af0646e213391c4cb7a09c68abeb0f7929 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java
@@ -22,12 +22,7 @@
  */
 package com.oracle.truffle.r.runtime.data.closures;
 
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RDouble;
-import com.oracle.truffle.r.runtime.data.RInteger;
-import com.oracle.truffle.r.runtime.data.RLogical;
-import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RString;
+import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -122,19 +117,21 @@ public class RClosures {
         if (levels == null) {
             return new RFactorToStringVectorClosure(factor, null, withNames);
         } else {
-            if (levels.getElementClass() == RInteger.class) {
-                return new RFactorToIntVectorClosure(factor, (RAbstractIntVector) levels, withNames);
-            } else if (levels.getElementClass() == RDouble.class) {
-                return new RFactorToDoubleVectorClosure(factor, (RAbstractDoubleVector) levels, withNames);
-            } else if (levels.getElementClass() == RLogical.class) {
-                return new RFactorToIntVectorClosure(factor, createLogicalToIntVector((RAbstractLogicalVector) levels), withNames);
-            } else if (levels.getElementClass() == RComplex.class) {
-                return new RFactorToComplexVectorClosure(factor, (RAbstractComplexVector) levels, withNames);
-            } else if (levels.getElementClass() == RString.class) {
-                return new RFactorToStringVectorClosure(factor, (RAbstractStringVector) levels, withNames);
-            } else {
-                assert levels.getElementClass() == RRaw.class;
-                return new RFactorToIntVectorClosure(factor, createRawToIntVector((RAbstractRawVector) levels), withNames);
+            switch (levels.getRType()) {
+                case Integer:
+                    return new RFactorToIntVectorClosure(factor, (RAbstractIntVector) levels, withNames);
+                case Double:
+                    return new RFactorToDoubleVectorClosure(factor, (RAbstractDoubleVector) levels, withNames);
+                case Logical:
+                    return new RFactorToIntVectorClosure(factor, createLogicalToIntVector((RAbstractLogicalVector) levels), withNames);
+                case Complex:
+                    return new RFactorToComplexVectorClosure(factor, (RAbstractComplexVector) levels, withNames);
+                case Character:
+                    return new RFactorToStringVectorClosure(factor, (RAbstractStringVector) levels, withNames);
+                case Raw:
+                    return new RFactorToIntVectorClosure(factor, createRawToIntVector((RAbstractRawVector) levels), withNames);
+                default:
+                    throw RInternalError.shouldNotReachHere();
             }
         }
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
index 3ad93d63f6978b9cc587d5fbd5573e5f34cc991d..b2d9e6cd06d0ad7e508393bfe0f29004d3e6f8f4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java
@@ -62,9 +62,4 @@ public interface RAbstractComplexVector extends RAbstractAtomicVector {
     default RType getRType() {
         return RType.Complex;
     }
-
-    @Override
-    default Class<?> getElementClass() {
-        return RComplex.class;
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
index f03140b082be971d317912a12de4a7024e7aeb96..5afbae372907df8ac0f98640c8a71f1ce1a17f66 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
@@ -43,8 +43,6 @@ public interface RAbstractContainer extends RAttributable, RTypedValue {
 
     void setDimensions(int[] newDimensions);
 
-    Class<?> getElementClass();
-
     RTypedValue getNonShared();
 
     RAbstractContainer materialize();
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
index 8bfd1573077131338384384b95014682a898dc7a..ab8c782a3f97d0e8882eb8d551d50debf22905f0 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java
@@ -24,7 +24,6 @@ package com.oracle.truffle.r.runtime.data.model;
 
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 
 public interface RAbstractDoubleVector extends RAbstractAtomicVector {
@@ -62,9 +61,4 @@ public interface RAbstractDoubleVector extends RAbstractAtomicVector {
     default RType getRType() {
         return RType.Double;
     }
-
-    @Override
-    default Class<?> getElementClass() {
-        return RDouble.class;
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
index bc64990d6114804f91779463a367bd057c302b27..92401aea21e6a7f5a42f0c130ab62b3c716806ce 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java
@@ -25,7 +25,6 @@ package com.oracle.truffle.r.runtime.data.model;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RInteger;
 
 public interface RAbstractIntVector extends RAbstractAtomicVector {
 
@@ -62,9 +61,4 @@ public interface RAbstractIntVector extends RAbstractAtomicVector {
     default RType getRType() {
         return RType.Integer;
     }
-
-    @Override
-    default Class<?> getElementClass() {
-        return RInteger.class;
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java
index edd08c2347b8d0ed755d8e46f1abb0b5e52cd4c7..31ceb508163554eedbe07f546c1465c37e938657 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java
@@ -34,18 +34,13 @@ public interface RAbstractListBaseVector extends RAbstractVector {
 
     Object getDataAt(int index);
 
-    @Override
-    default boolean checkCompleteness() {
-        return true;
-    }
-
-    @Override
-    default Class<?> getElementClass() {
-        return Object.class;
-    }
-
     @SuppressWarnings("unused")
     default void setDataAt(Object store, int index, Object value) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    default boolean checkCompleteness() {
+        return true;
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
index abb58b0adb2308d62398abacb6137218b404d86e..2a1c503de5361dcd250c061344b5c621f97c0e8a 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java
@@ -24,7 +24,6 @@ package com.oracle.truffle.r.runtime.data.model;
 
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 
 public interface RAbstractLogicalVector extends RAbstractAtomicVector {
@@ -62,9 +61,4 @@ public interface RAbstractLogicalVector extends RAbstractAtomicVector {
     default RType getRType() {
         return RType.Logical;
     }
-
-    @Override
-    default Class<?> getElementClass() {
-        return RLogical.class;
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
index 38441f5fb118b2c322746bf2f024ff842c49dec8..202f841cd2d6879829b6652a98ef6c93e2c858e9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java
@@ -58,9 +58,4 @@ public interface RAbstractRawVector extends RAbstractAtomicVector {
     default RType getRType() {
         return RType.Raw;
     }
-
-    @Override
-    default Class<?> getElementClass() {
-        return RRaw.class;
-    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
index 032c8bed11216dd37a72c1670fc29b547e421436..af93f141e09f2791c2e7fcc4b809b2302ce22355 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java
@@ -24,7 +24,6 @@ package com.oracle.truffle.r.runtime.data.model;
 
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.data.RString;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 
 public interface RAbstractStringVector extends RAbstractAtomicVector {
@@ -62,9 +61,4 @@ public interface RAbstractStringVector extends RAbstractAtomicVector {
     default RType getRType() {
         return RType.Character;
     }
-
-    @Override
-    default Class<?> getElementClass() {
-        return RString.class;
-    }
 }
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 ec06e4b77c6c712000752a53bf210ade6cb05f88..b8fb83303e2caa6aac949146fb457817ef73d73e 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
@@ -67557,6 +67557,128 @@ model.frame     predict   residuals
 #argv <- list('> ### R code from vignette source \'parallel.Rnw\'\n> \n> ###################################################\n> ### code chunk number 1: parallel.Rnw:474-475 (eval = FALSE)\n> ###################################################\n> ## library(parallel)\n> \n> \n> ###################################################\n> ### code chunk number 2: parallel.Rnw:500-507 (eval = FALSE)\n> ###################################################\n> ## library(boot)\n> ## cd4.rg <- function(data, mle) MASS::mvrnorm(nrow(data), mle$m, mle$v)\n> ## cd4.mle <- list(m = colMeans(cd4), v = var(cd4))\n> ## cd4.boot <- boot(cd4, corr, R = 999, sim = \'parametric\',\n> ##                  ran.gen = cd4.rg, mle = cd4.mle)\n> ## boot.ci(cd4.boot,  type = c(\'norm\', \'basic\', \'perc\'),\n> ##         conf = 0.9, h = atanh, hinv = tanh)\n> \n> \n> ###################################################\n> ### code chunk number 3: parallel.Rnw:512-522 (eval = FALSE)\n> ###################################################\n> ## cd4.rg <- function(data, mle) MASS::mvrnorm(nrow(data), mle$m, mle$v)\n> ## cd4.mle <- list(m = colMeans(cd4), v = var(cd4))\n> ## run1 <- function(...) boot(cd4, corr, R = 500, sim = \'parametric\',\n> ##                            ran.gen = cd4.rg, mle = cd4.mle)\n> ## mc <- 2 # set as appropriate for your hardware\n> ## ## To make this reproducible:\n> ## set.seed(123, \'L\'Ecuyer\')\n> ## cd4.boot <- do.call(c, mclapply(seq_len(mc), run1) )\n> ## boot.ci(cd4.boot,  type = c(\'norm\', \'basic\', \'perc\'),\n> ##         conf = 0.9, h = atanh, hinv = tanh)\n> \n> \n> ###################################################\n> ### code chunk number 4: parallel.Rnw:527-528 (eval = FALSE)\n> ###################################################\n> ## do.call(c, lapply(seq_len(mc), run1))\n> \n> \n> ###################################################\n> ### code chunk number 5: parallel.Rnw:532-547 (eval = FALSE)\n> ###################################################\n> ## run1 <- function(...) {\n> ##    library(boot)\n> ##    cd4.rg <- function(data, mle) MASS::mvrnorm(nrow(data), mle$m, mle$v)\n> ##    cd4.mle <- list(m = colMeans(cd4), v = var(cd4))\n> ##    boot(cd4, corr, R = 500, sim = \'parametric\',\n> ##         ran.gen = cd4.rg, mle = cd4.mle)\n> ## }\n> ## cl <- makeCluster(mc)\n> ## ## make this reproducible\n> ## clusterSetRNGStream(cl, 123)\n> ## library(boot) # needed for c() method on master\n> ## cd4.boot <- do.call(c, parLapply(cl, seq_len(mc), run1) )\n> ## boot.ci(cd4.boot,  type = c(\'norm\', \'basic\', \'perc\'),\n> ##         conf = 0.9, h = atanh, hinv = tanh)\n> ## stopCluster(cl)\n> \n> \n> ###################################################\n> ### code chunk number 6: parallel.Rnw:557-570 (eval = FALSE)\n> ###################################################\n> ## cl <- makeCluster(mc)\n> ## cd4.rg <- function(data, mle) MASS::mvrnorm(nrow(data), mle$m, mle$v)\n> ## cd4.mle <- list(m = colMeans(cd4), v = var(cd4))\n> ## clusterExport(cl, c(\'cd4.rg\', \'cd4.mle\'))\n> ## junk <- clusterEvalQ(cl, library(boot)) # discard result\n> ## clusterSetRNGStream(cl, 123)\n> ## res <- clusterEvalQ(cl, boot(cd4, corr, R = 500,\n> ##                     sim = \'parametric\', ran.gen = cd4.rg, mle = cd4.mle))\n> ## library(boot) # needed for c() method on master\n> ## cd4.boot <- do.call(c, res)\n> ## boot.ci(cd4.boot,  type = c(\'norm\', \'basic\', \'perc\'),\n> ##         conf = 0.9, h = atanh, hinv = tanh)\n> ## stopCluster(cl)\n> \n> \n> ###################################################\n> ### code chunk number 7: parallel.Rnw:575-589 (eval = FALSE)\n> ###################################################\n> ## R <- 999; M <- 999 ## we would like at least 999 each\n> ## cd4.nest <- boot(cd4, nested.corr, R=R, stype=\'w\', t0=corr(cd4), M=M)\n> ## ## nested.corr is a function in package boot\n> ## op <- par(pty = \'s\', xaxs = \'i\', yaxs = \'i\')\n> ## qqplot((1:R)/(R+1), cd4.nest$t[, 2], pch = \'.\', asp = 1,\n> ##         xlab = \'nominal\', ylab = \'estimated\')\n> ## abline(a = 0, b = 1, col = \'grey\')\n> ## abline(h = 0.05, col = \'grey\')\n> ## abline(h = 0.95, col = \'grey\')\n> ## par(op)\n> ## \n> ## nominal <- (1:R)/(R+1)\n> ## actual <- cd4.nest$t[, 2]\n> ## 100*nominal[c(sum(actual <= 0.05), sum(actual < 0.95))]\n> \n> \n> ###################################################\n> ### code chunk number 8: parallel.Rnw:594-602 (eval = FALSE)\n> ###################################################\n> ## mc <- 9\n> ## R <- 999; M <- 999; RR <- floor(R/mc)\n> ## run2 <- function(...)\n> ##     cd4.nest <- boot(cd4, nested.corr, R=RR, stype=\'w\', t0=corr(cd4), M=M)\n> ## cd4.nest <- do.call(c, mclapply(seq_len(mc), run2, mc.cores = mc) )\n> ## nominal <- (1:R)/(R+1)\n> ## actual <- cd4.nest$t[, 2]\n> ## 100*nominal[c(sum(actual <= 0.05), sum(actual < 0.95))]\n> \n> \n> ###################################################\n> ### code chunk number 9: parallel.Rnw:616-627 (eval = FALSE)\n> ###################################################\n> ## library(spatial)\n> ## towns <- ppinit(\'towns.dat\')\n> ## tget <- function(x, r=3.5) sum(dist(cbind(x$x, x$y)) < r)\n> ## t0 <- tget(towns)\n> ## R <- 1000\n> ## c <- seq(0, 1, 0.1)\n> ## ## res[1] = 0\n> ## res <- c(0, sapply(c[-1], function(c)\n> ##     mean(replicate(R, tget(Strauss(69, c=c, r=3.5))))))\n> ## plot(c, res, type=\'l\', ylab=\'E t\')\n> ## abline(h=t0, col=\'grey\')\n> \n> \n> ###################################################\n> ### code chunk number 10: parallel.Rnw:631-640 (eval = FALSE)\n> ###################################################\n> ## run3 <- function(c) {\n> ##     library(spatial)\n> ##     towns <- ppinit(\'towns.dat\') # has side effects\n> ##     mean(replicate(R, tget(Strauss(69, c=c, r=3.5))))\n> ## }\n> ## cl <- makeCluster(10, methods = FALSE)\n> ## clusterExport(cl, c(\'R\', \'towns\', \'tget\'))\n> ## res <- c(0, parSapply(cl, c[-1], run3)) # 10 tasks\n> ## stopCluster(cl)\n> \n> \n> ###################################################\n> ### code chunk number 11: parallel.Rnw:644-648 (eval = FALSE)\n> ###################################################\n> ## cl <- makeForkCluster(10)  # fork after the variables have been set up\n> ## run4 <- function(c)  mean(replicate(R, tget(Strauss(69, c=c, r=3.5))))\n> ## res <- c(0, parSapply(cl, c[-1], run4))\n> ## stopCluster(cl)\n> \n> \n> ###################################################\n> ### code chunk number 12: parallel.Rnw:651-653 (eval = FALSE)\n> ###################################################\n> ## run4 <- function(c)  mean(replicate(R, tget(Strauss(69, c=c, r=3.5))))\n> ## res <- c(0, unlist(mclapply(c[-1], run4, mc.cores = 10)))\n> \n> \n> ###################################################\n> ### code chunk number 13: parallel.Rnw:684-718 (eval = FALSE)\n> ###################################################\n> ## pkgs <- \'<names of packages to be installed>\'\n> ## M <- 20 # number of parallel installs\n> ## M <- min(M, length(pkgs))\n> ## library(parallel)\n> ## unlink(\'install_log\')\n> ## cl <- makeCluster(M, outfile = \'install_log\')\n> ## clusterExport(cl, c(\'tars\', \'fakes\', \'gcc\')) # variables needed by do_one\n> ## \n> ## ## set up available via a call to available.packages() for\n> ## ## repositories containing all the packages involved and all their\n> ## ## dependencies.\n> ## DL <- utils:::.make_dependency_list(pkgs, available, recursive = TRUE)\n> ## DL <- lapply(DL, function(x) x[x %in% pkgs])\n> ## lens <- sapply(DL, length)\n> ## ready <- names(DL[lens == 0L])\n> ## done <- character() # packages already installed\n> ## n <- length(ready)\n> ## submit <- function(node, pkg)\n> ##     parallel:::sendCall(cl[[node]], do_one, list(pkg), tag = pkg)\n> ## for (i in 1:min(n, M)) submit(i, ready[i])\n> ## DL <- DL[!names(DL) %in% ready[1:min(n, M)]]\n> ## av <- if(n < M) (n+1L):M else integer() # available workers\n> ## while(length(done) < length(pkgs)) {\n> ##     d <- parallel:::recvOneResult(cl)\n> ##     av <- c(av, d$node)\n> ##     done <- c(done, d$tag)\n> ##     OK <- unlist(lapply(DL, function(x) all(x %in% done) ))\n> ##     if (!any(OK)) next\n> ##     p <- names(DL)[OK]\n> ##     m <- min(length(p), length(av)) # >= 1\n> ##     for (i in 1:m) submit(av[i], p[i])\n> ##     av <- av[-(1:m)]\n> ##     DL <- DL[!names(DL) %in% p[1:m]]\n> ## }\n> \n> \n> ###################################################\n> ### code chunk number 14: parallel.Rnw:731-748 (eval = FALSE)\n> ###################################################\n> ##     fn <- function(r) statistic(data, i[r, ], ...)\n> ##     RR <- sum(R)\n> ##     res <- if (ncpus > 1L && (have_mc || have_snow)) {\n> ##         if (have_mc) {\n> ##             parallel::mclapply(seq_len(RR), fn, mc.cores = ncpus)\n> ##         } else if (have_snow) {\n> ##             list(...) # evaluate any promises\n> ##             if (is.null(cl)) {\n> ##                 cl <- parallel::makePSOCKcluster(rep(\'localhost\', ncpus))\n> ##                 if(RNGkind()[1L] == \'L\'Ecuyer-CMRG\')\n> ##                     parallel::clusterSetRNGStream(cl)\n> ##                 res <- parallel::parLapply(cl, seq_len(RR), fn)\n> ##                 parallel::stopCluster(cl)\n> ##                 res\n> ##             } else parallel::parLapply(cl, seq_len(RR), fn)\n> ##         }\n> ##     } else lapply(seq_len(RR), fn)\n> \n> \n> ###################################################\n> ### code chunk number 15: parallel.Rnw:751-752 (eval = FALSE)\n> ###################################################\n> ##             list(...) # evaluate any promises\n> \n> ', 1L, 150L); .Internal(substr(argv[[1]], argv[[2]], argv[[3]]))
 [1] "> ### R code from vignette source 'parallel.Rnw'\n> \n> ###################################################\n> ### code chunk number 1: parallel.Rnw:474-"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -1L, -1L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -1L, -2L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -1L, 0L, 'xyz')
+[1] "ffff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -1L, 1L, 'xyz')
+[1] "xfff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -1L, 2L, 'xyz')
+[1] "xyff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -2L, -1L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -2L, -2L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -2L, 0L, 'xyz')
+[1] "ffff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -2L, 1L, 'xyz')
+[1] "xfff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', -2L, 2L, 'xyz')
+[1] "xyff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 0L, -1L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 0L, -2L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 0L, 0L, 'xyz')
+[1] "ffff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 0L, 1L, 'xyz')
+[1] "xfff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 0L, 2L, 'xyz')
+[1] "xyff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 1L, -1L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 1L, -2L, 'xyz')
+[1] "xyzf"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 1L, 0L, 'xyz')
+[1] "ffff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 1L, 1L, 'xyz')
+[1] "xfff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 1L, 2L, 'xyz')
+[1] "xyff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 2L, -1L, 'xyz')
+[1] "fxyz"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 2L, -2L, 'xyz')
+[1] "fxyz"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 2L, 0L, 'xyz')
+[1] "ffff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 2L, 1L, 'xyz')
+[1] "ffff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`('ffff', 2L, 2L, 'xyz')
+[1] "fxff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, 5, 1)
+Error in `substr<-`(c("asdfasdf", "jfjfjf", "ffff"), 2, 5, 1) :
+  invalid value
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, 5, NULL)
+Error in `substr<-`(c("asdfasdf", "jfjfjf", "ffff"), 2, 5, NULL) :
+  invalid value
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, 5, c('a', 'asdf'))
+[1] "aadfasdf" "jasdff"   "faff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, c(5,15,-6), c('a', 'asdf'))
+[1] "aadfasdf" "jasdff"   "faff"
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign#
+#`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), c(1,10,-6), 5, c('a', 'asdf'))
+[1] "asdfasdf" "jfjfjf"   "afff"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign1#
 #argv <- list('(0,5]', 1L, 1L, '['); .Internal(`substr<-`(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))
 [1] "[0,5]"
@@ -67566,11 +67688,11 @@ model.frame     predict   residuals
 [1] "a..ef"           "q+++ty"          "y..op["          "b"
 [5] "s..ff.blah.yech"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign_.testsubstrassign_1#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign_1#
 #argv <- structure(list(x = c('NA', NA, 'BANANA'), start = 1,     stop = 2, value = 'na'), .Names = c('x', 'start', 'stop',     'value'));do.call('substr<-', argv)
 [1] "na"     NA       "naNANA"
 
-##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign_.testsubstrassign_2#
+##com.oracle.truffle.r.test.builtins.TestBuiltin_substrassign.testsubstrassign_2#
 #argv <- structure(list(x = 'abcde', start = NA, stop = 3, value = 'abc'),     .Names = c('x', 'start', 'stop', 'value'));do.call('substr<-', argv)
 [1] NA
 
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign.java
index a0a36c9829aac61986ad632c630c303b315b802f..a5e1bdc82233ea2098eb3b21ea9832a26ea7ee07 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign.java
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -26,4 +26,26 @@ public class TestBuiltin_substrassign extends TestBase {
     public void testsubstrassign2() {
         assertEval("argv <- list(c('asfef', 'qwerty', 'yuiop[', 'b', 'stuff.blah.yech'), 2L, 1000000L, c('..', '+++')); .Internal(`substr<-`(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))");
     }
+
+    @Test
+    public void testsubstrassign_1() {
+        assertEval("argv <- structure(list(x = c('NA', NA, 'BANANA'), start = 1,     stop = 2, value = 'na'), .Names = c('x', 'start', 'stop',     'value'));do.call('substr<-', argv)");
+    }
+
+    @Test
+    public void testsubstrassign_2() {
+        assertEval("argv <- structure(list(x = 'abcde', start = NA, stop = 3, value = 'abc'),     .Names = c('x', 'start', 'stop', 'value'));do.call('substr<-', argv)");
+    }
+
+    @Test
+    public void testsubstrassign() {
+        assertEval("`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, 5, c('a', 'asdf'))");
+        assertEval("`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), c(1,10,-6), 5, c('a', 'asdf'))");
+        assertEval("`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, c(5,15,-6), c('a', 'asdf'))");
+        assertEval("`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, 5, NULL)");
+        assertEval("`substr<-`(c('asdfasdf', 'jfjfjf', 'ffff'), 2, 5, 1)");
+
+        String[] values = new String[]{"-2L", "-1L", "0L", "1L", "2L"};
+        assertEval(template("`substr<-`('ffff', %0, %1, 'xyz')", values, values));
+    }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign_.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign_.java
deleted file mode 100644
index 2573d8eefbd23b1659ad77b0f7a35465a905fbe4..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign_.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * This material is distributed under the GNU General Public License
- * Version 2. You may review the terms of this license at
- * http://www.gnu.org/licenses/gpl-2.0.html
- *
- * Copyright (c) 2014, Purdue University
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates
- *
- * All rights reserved.
- */
-package com.oracle.truffle.r.test.builtins;
-
-import org.junit.Test;
-
-import com.oracle.truffle.r.test.TestBase;
-
-// Checkstyle: stop line length check
-
-public class TestBuiltin_substrassign_ extends TestBase {
-
-    @Test
-    public void testsubstrassign_1() {
-        assertEval("argv <- structure(list(x = c('NA', NA, 'BANANA'), start = 1,     stop = 2, value = 'na'), .Names = c('x', 'start', 'stop',     'value'));do.call('substr<-', argv)");
-    }
-
-    @Test
-    public void testsubstrassign_2() {
-        assertEval("argv <- structure(list(x = 'abcde', start = NA, stop = 3, value = 'abc'),     .Names = c('x', 'start', 'stop', 'value'));do.call('substr<-', argv)");
-    }
-}
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index d3c6075238f30f0347d2ed8f3bb85f70613cd644..eaa941e25e3e765f44062e9eee1f78ce6d8e8bf8 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -658,7 +658,6 @@ com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sub
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_subset2.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substitute.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substr.java,purdue.copyright
-com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign_.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substrassign.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_substring.java,purdue.copyright
 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sum.java,purdue.copyright