diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java
index 0bce74744dc62ef55b09ffbd5568067ce7084672..a5a57f7b338a8acd950575d63bd37eb8e3e44e64 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.r.ffi.impl.nodes;
 
-import java.util.Arrays;
-
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -45,6 +43,7 @@ import com.oracle.truffle.r.runtime.data.RPairList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RSymbol;
 import com.oracle.truffle.r.runtime.data.RTypes;
+import com.oracle.truffle.r.runtime.data.nodes.GetDataCopy;
 
 /**
  * Nodes that implement {@code CAR}, {@code CDR}, etc. N.B. GNU R does not error check the
@@ -114,17 +113,17 @@ public final class ListAccessNodes {
 
         @Specialization
         protected Object cdr(RList list,
+                        @Cached("create()") GetDataCopy.String getDataCopyNode,
                         @Cached("create()") GetNamesAttributeNode getNamesNode,
                         @Cached("create()") SetNamesAttributeNode setNamesNode) {
             if (list.getLength() == 1) {
                 return RNull.instance;
             }
-            Object[] dataCopy = list.getDataWithoutCopying();
             RStringVector names = getNamesNode.getNames(list);
-            RList copy = RDataFactory.createList(Arrays.copyOfRange(dataCopy, 1, list.getLength()));
+            RList copy = RDataFactory.createList(list.getDataCopy());
             if (names != null) {
-                String[] dataWithoutCopying = names.getDataWithoutCopying();
-                setNamesNode.setNames(copy, RDataFactory.createStringVector(Arrays.copyOfRange(dataWithoutCopying, 1, names.getLength()), true));
+                String[] namesDataCopy = getDataCopyNode.execute(names);
+                setNamesNode.setNames(copy, RDataFactory.createStringVector(namesDataCopy, true));
             }
             return copy;
         }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
index e9b73da1514c22210656f0301bff85c889a10ec6..cffbaad71f9c59b41e3cae935605ccf4bf441156 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java
@@ -25,6 +25,8 @@ import com.oracle.truffle.r.nodes.attributes.SetAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
@@ -32,8 +34,6 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector.DoubleAccessor;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
 public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
@@ -51,7 +51,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
 
     @Specialization(guards = "method == cachedMethod")
     protected RDoubleVector cdist(RAbstractDoubleVector x, @SuppressWarnings("unused") int method, RList list, double p, @SuppressWarnings("unused") @Cached("method") int cachedMethod,
-                    @Cached("new()") AccessVector.Double xAccess,
+                    @Cached("create()") VectorReadAccess.Double xAccess,
                     @Cached("getMethod(method)") Method methodObj,
                     @Cached("create()") SetAttributeNode setAttrNode,
                     @Cached("create()") SetClassAttributeNode setClassAttrNode,
@@ -61,7 +61,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         int n = nr * (nr - 1) / 2; /* avoid int overflow for N ~ 50,000 */
         double[] ans = new double[n];
         RDoubleVector xm = x.materialize();
-        rdistance(new DoubleAccessor(x, xAccess), nr, nc, ans, false, methodObj, p);
+        rdistance(new ReadAccessor.Double(x, xAccess), nr, nc, ans, false, methodObj, p);
         RDoubleVector result = RDataFactory.createDoubleVector(ans, naCheck.neverSeenNA());
         DynamicObject resultAttrs = result.initAttributes();
 
@@ -96,7 +96,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         return Method.values()[method - 1];
     }
 
-    private void rdistance(DoubleAccessor xAccess, int nr, int nc, double[] d, boolean diag, Method method, double p) {
+    private void rdistance(ReadAccessor.Double xAccess, int nr, int nc, double[] d, boolean diag, Method method, double p) {
         int ij; /* can exceed 2^31 - 1, but Java can't handle that */
         //
         if (method == Method.MINKOWSKI) {
@@ -119,7 +119,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
     public enum Method {
         EUCLIDEAN {
             @Override
-            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -152,7 +152,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MAXIMUM {
             @Override
-            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -184,7 +184,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MANHATTAN {
             @Override
-            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -217,7 +217,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         CANBERRA {
             @Override
-            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -258,7 +258,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         BINARY {
             @Override
-            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 int total;
@@ -300,7 +300,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MINKOWSKI {
             @Override
-            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -331,6 +331,6 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
             }
         };
 
-        public abstract double dist(DoubleAccessor xAccess, int nr, int nc, int i1, int i2, double p);
+        public abstract double dist(ReadAccessor.Double xAccess, int nr, int nc, int i1, int i2, double p);
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
index 283a18303f840f13a145e68646bccbb85737f8c6..5b1928a954265a3a102a64432cc8678f717d0e9a 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java
@@ -16,6 +16,7 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 
 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.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
@@ -33,6 +34,8 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 import com.oracle.truffle.r.runtime.nmath.RMath;
 
 /*
@@ -70,20 +73,20 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
     /**
      * Compute Cov(xx[], yy[]) or Cor(.,.) with n = length(xx)
      */
-    private static void COV_PAIRWISE_BODY(double[] ans, int n, int ncx, int i, int j, double[] x, double[] y, int xx, int yy, boolean[] sd_0, boolean cor, boolean kendall) {
+    private static void COV_PAIRWISE_BODY(double[] ans, int n, int ncx, int i, int j, ReadAccessor.Double x, ReadAccessor.Double y, int xx, int yy, boolean[] sd_0, boolean cor, boolean kendall) {
         double xmean = 0, ymean = 0;
         int nobs = 0;
         if (!kendall) {
             for (int k = 0; k < n; k++) {
-                if (!(ISNAN(x[xx + k]) || ISNAN(y[yy + k]))) {
+                if (!(ISNAN(x.getDataAt(xx + k)) || ISNAN(y.getDataAt(yy + k)))) {
                     nobs++;
-                    xmean += x[xx + k];
-                    ymean += y[yy + k];
+                    xmean += x.getDataAt(xx + k);
+                    ymean += y.getDataAt(yy + k);
                 }
             }
         } else /* kendall */
             for (int k = 0; k < n; k++) {
-                if (!(ISNAN(x[xx + k]) || ISNAN(y[yy + k]))) {
+                if (!(ISNAN(x.getDataAt(xx + k)) || ISNAN(y.getDataAt(yy + k)))) {
                     nobs++;
                 }
             }
@@ -97,10 +100,10 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 n1 = nobs - 1;
             }
             for (int k = 0; k < n; k++) {
-                if (!(ISNAN(x[xx + k]) || ISNAN(y[yy + k]))) {
+                if (!(ISNAN(x.getDataAt(xx + k)) || ISNAN(y.getDataAt(yy + k)))) {
                     if (!kendall) {
-                        double xm = x[xx + k] - xmean;
-                        double ym = y[yy + k] - ymean;
+                        double xm = x.getDataAt(xx + k) - xmean;
+                        double ym = y.getDataAt(yy + k) - ymean;
 
                         sum += xm * ym;
                         if (cor) {
@@ -111,9 +114,9 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
 
                     else { /* Kendall's tau */
                         for (n1 = 0; n1 < k; n1++) {
-                            if (!(ISNAN(x[xx + n1]) || ISNAN(y[yy + n1]))) {
-                                double xm = RMath.sign(x[xx + k] - x[xx + n1]);
-                                double ym = RMath.sign(y[yy + k] - y[yy + n1]);
+                            if (!(ISNAN(x.getDataAt(xx + n1)) || ISNAN(y.getDataAt(yy + n1)))) {
+                                double xm = RMath.sign(x.getDataAt(xx + k) - x.getDataAt(xx + n1));
+                                double ym = RMath.sign(y.getDataAt(yy + k) - y.getDataAt(yy + n1));
 
                                 sum += xm * ym;
                                 if (cor) {
@@ -148,7 +151,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void cov_pairwise1(int n, int ncx, double[] x, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
+    private static void cov_pairwise1(int n, int ncx, ReadAccessor.Double x, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
         for (int i = 0; i < ncx; i++) {
             int xx = i * n;
             for (int j = 0; j <= i; j++) {
@@ -161,7 +164,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void cov_pairwise2(int n, int ncx, int ncy, double[] x, double[] y, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
+    private static void cov_pairwise2(int n, int ncx, int ncy, ReadAccessor.Double x, ReadAccessor.Double y, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
         for (int i = 0; i < ncx; i++) {
             int xx = i * n;
             for (int j = 0; j < ncy; j++) {
@@ -177,14 +180,14 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
      */
 
     /* This uses two passes for better accuracy */
-    private static void MEAN(int n, int ncx, double[] x, double[] xm, boolean[] ind, int nobs) {
+    private static void MEAN(int n, int ncx, ReadAccessor.Double x, double[] xm, boolean[] ind, int nobs) {
         /* variable means */
         for (int i = 0; i < ncx; i++) {
             int xx = i * n;
             double sum = 0;
             for (int k = 0; k < n; k++) {
                 if (ind[k]) {
-                    sum += x[xx + k];
+                    sum += x.getDataAt(xx + k);
                 }
             }
             double tmp = sum / nobs;
@@ -192,7 +195,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 sum = 0;
                 for (int k = 0; k < n; k++) {
                     if (ind[k]) {
-                        sum += (x[xx + k] - tmp);
+                        sum += (x.getDataAt(xx + k) - tmp);
                     }
                 }
                 tmp = tmp + sum / nobs;
@@ -202,7 +205,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
     }
 
     /* This uses two passes for better accuracy */
-    private static void MEAN_(int n, int ncx, double[] x, double[] xm, boolean[] has_na) {
+    private static void MEAN_(int n, int ncx, ReadAccessor.Double x, double[] xm, boolean[] has_na) {
         /* variable means (has_na) */
         for (int i = 0; i < ncx; i++) {
             double tmp;
@@ -212,13 +215,13 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 int xx = i * n;
                 double sum = 0;
                 for (int k = 0; k < n; k++) {
-                    sum += x[xx + k];
+                    sum += x.getDataAt(xx + k);
                 }
                 tmp = sum / n;
                 if (Double.isFinite(tmp)) {
                     sum = 0;
                     for (int k = 0; k < n; k++) {
-                        sum += (x[xx + k] - tmp);
+                        sum += (x.getDataAt(xx + k) - tmp);
                     }
                     tmp = tmp + sum / n;
                 }
@@ -227,7 +230,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void cov_complete1(int n, int ncx, double[] x, double[] xm, boolean[] ind, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
+    private static void cov_complete1(int n, int ncx, ReadAccessor.Double x, double[] xm, boolean[] ind, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
         int n1 = -1;
 
         /* total number of complete observations */
@@ -261,7 +264,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                     double sum = 0;
                     for (int k = 0; k < n; k++) {
                         if (ind[k]) {
-                            sum += (x[xx + k] - xxm) * (x[yy + k] - yym);
+                            sum += (x.getDataAt(xx + k) - xxm) * (x.getDataAt(yy + k) - yym);
                         }
                     }
                     double result = sum / n1;
@@ -276,7 +279,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                         if (ind[k]) {
                             for (n1 = 0; n1 < n; n1++) {
                                 if (ind[n1]) {
-                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(x[yy + k] - x[yy + n1]);
+                                    sum += RMath.sign(x.getDataAt(xx + k) - x.getDataAt(xx + n1)) * RMath.sign(x.getDataAt(yy + k) - x.getDataAt(yy + n1));
                                 }
                             }
                         }
@@ -313,7 +316,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void cov_na_1(int n, int ncx, double[] x, double[] xm, boolean[] has_na, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
+    private static void cov_na_1(int n, int ncx, ReadAccessor.Double x, double[] xm, boolean[] has_na, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
         int n1 = -1;
         if (n <= 1) { /* too many missing */
             for (int i = 0; i < ncx; i++) {
@@ -348,7 +351,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                             double yym = xm[j];
                             double sum = 0;
                             for (int k = 0; k < n; k++) {
-                                sum += (x[xx + k] - xxm) * (x[yy + k] - yym);
+                                sum += (x.getDataAt(xx + k) - xxm) * (x.getDataAt(yy + k) - yym);
                             }
                             double result = sum / n1;
                             ANS(ans, ncx, j, i, result);
@@ -365,7 +368,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                             double sum = 0;
                             for (int k = 0; k < n; k++) {
                                 for (n1 = 0; n1 < n; n1++) {
-                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(x[yy + k] - x[yy + n1]);
+                                    sum += RMath.sign(x.getDataAt(xx + k) - x.getDataAt(xx + n1)) * RMath.sign(x.getDataAt(yy + k) - x.getDataAt(yy + n1));
                                 }
                             }
                             ANS(ans, ncx, j, i, sum);
@@ -406,7 +409,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void COV_SDEV1(int n, int n1, int nc, double[] array, double[] m, boolean[] ind, boolean kendall) {
+    private static void COV_SDEV1(int n, int n1, int nc, ReadAccessor.Double array, double[] m, boolean[] ind, boolean kendall) {
         for (int i = 0; i < nc; i++) { /* Var(X[i]) */
             int xx = i * n;
             double sum = 0;
@@ -414,7 +417,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 double xxm = m[i];
                 for (int k = 0; k < n; k++) {
                     if (ind[k]) {
-                        sum += (array[xx + k] - xxm) * (array[xx + k] - xxm);
+                        sum += (array.getDataAt(xx + k) - xxm) * (array.getDataAt(xx + k) - xxm);
                     }
                 }
                 sum /= n1;
@@ -422,7 +425,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 for (int k = 0; k < n; k++) {
                     if (ind[k]) {
                         for (int n1_ = 0; n1_ < n; n1_++) {
-                            if (ind[n1_] && array[xx + k] != array[xx + n1_]) {
+                            if (ind[n1_] && array.getDataAt(xx + k) != array.getDataAt(xx + n1_)) {
                                 sum++; /* = sign(. - .)^2 */
                             }
                         }
@@ -433,7 +436,8 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void cov_complete2(int n, int ncx, int ncy, double[] x, double[] y, double[] xm, double[] ym, boolean[] ind, double[] ans, boolean[] sd_0, boolean cor, boolean kendall) {
+    private static void cov_complete2(int n, int ncx, int ncy, ReadAccessor.Double x, ReadAccessor.Double y, double[] xm, double[] ym, boolean[] ind, double[] ans, boolean[] sd_0, boolean cor,
+                    boolean kendall) {
         int n1 = -1;
 
         /* total number of complete observations */
@@ -467,7 +471,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                     double sum = 0;
                     for (int k = 0; k < n; k++) {
                         if (ind[k]) {
-                            sum += (x[xx + k] - xxm) * (y[yy + k] - yym);
+                            sum += (x.getDataAt(xx + k) - xxm) * (y.getDataAt(yy + k) - yym);
                         }
                     }
                     ANS(ans, ncx, i, j, sum / n1);
@@ -480,7 +484,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                         if (ind[k]) {
                             for (n1 = 0; n1 < n; n1++) {
                                 if (ind[n1]) {
-                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(y[yy + k] - y[yy + n1]);
+                                    sum += RMath.sign(x.getDataAt(xx + k) - x.getDataAt(xx + n1)) * RMath.sign(y.getDataAt(yy + k) - y.getDataAt(yy + n1));
                                 }
                             }
                         }
@@ -515,7 +519,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void COV_SDEV2(int n, int n1, int nc, double[] array, double[] m, boolean[] has_na, boolean kendall) {
+    private static void COV_SDEV2(int n, int n1, int nc, ReadAccessor.Double array, double[] m, boolean[] has_na, boolean kendall) {
         for (int i = 0; i < nc; i++) {
             if (!has_na[i]) { /* Var(X[j]) */
                 int xx = i * n;
@@ -523,13 +527,13 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 if (!kendall) {
                     double xxm = m[i];
                     for (int k = 0; k < n; k++) {
-                        sum += (array[xx + k] - xxm) * (array[xx + k] - xxm);
+                        sum += (array.getDataAt(xx + k) - xxm) * (array.getDataAt(xx + k) - xxm);
                     }
                     sum /= n1;
                 } else { /* Kendall's tau */
                     for (int k = 0; k < n; k++) {
                         for (int n1_ = 0; n1_ < n; n1_++) {
-                            if (array[xx + k] != array[xx + n1_]) {
+                            if (array.getDataAt(xx + k) != array.getDataAt(xx + n1_)) {
                                 sum++; /* = sign(. - .)^2 */
                             }
                         }
@@ -540,7 +544,8 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void cov_na_2(int n, int ncx, int ncy, double[] x, double[] y, double[] xm, double[] ym, boolean[] has_na_x, boolean[] has_na_y, double[] ans, boolean[] sd_0, boolean cor,
+    private static void cov_na_2(int n, int ncx, int ncy, ReadAccessor.Double x, ReadAccessor.Double y, double[] xm, double[] ym, boolean[] has_na_x, boolean[] has_na_y, double[] ans, boolean[] sd_0,
+                    boolean cor,
                     boolean kendall) {
         int n1 = -1;
         if (n <= 1) {/* too many missing */
@@ -574,7 +579,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                             double yym = ym[j];
                             double sum = 0;
                             for (int k = 0; k < n; k++) {
-                                sum += (x[xx + k] - xxm) * (y[yy + k] - yym);
+                                sum += (x.getDataAt(xx + k) - xxm) * (y.getDataAt(yy + k) - yym);
                             }
                             ANS(ans, ncx, i, j, sum / n1);
                         }
@@ -588,7 +593,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                             double sum = 0;
                             for (int k = 0; k < n; k++) {
                                 for (n1 = 0; n1 < n; n1++) {
-                                    sum += RMath.sign(x[xx + k] - x[xx + n1]) * RMath.sign(y[yy + k] - y[yy + n1]);
+                                    sum += RMath.sign(x.getDataAt(xx + k) - x.getDataAt(xx + n1)) * RMath.sign(y.getDataAt(yy + k) - y.getDataAt(yy + n1));
                                 }
                             }
                             ANS(ans, ncx, i, j, sum);
@@ -636,9 +641,9 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
      * This might look slightly inefficient, but it is designed to optimise paging in virtual memory
      * systems ... (or at least that's my story, and I'm sticking to it.)
      */
-    private static void NA_LOOP(int n, int z, double[] x, boolean[] ind, boolean na_fail) {
+    private static void NA_LOOP(int n, int z, ReadAccessor.Double x, boolean[] ind, boolean na_fail) {
         for (int i = 0; i < n; i++) {
-            if (ISNAN(x[z + i])) {
+            if (ISNAN(x.getDataAt(z + i))) {
                 if (na_fail) {
                     error("missing observations in cov/cor");
                 } else {
@@ -648,7 +653,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    private static void complete1(int n, int ncx, double[] x, boolean[] ind, boolean na_fail) {
+    private static void complete1(int n, int ncx, ReadAccessor.Double x, boolean[] ind, boolean na_fail) {
         for (int i = 0; i < n; i++) {
             ind[i] = true;
         }
@@ -658,7 +663,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    static void complete2(int n, int ncx, int ncy, double[] x, double[] y, boolean[] ind, boolean na_fail) {
+    static void complete2(int n, int ncx, int ncy, ReadAccessor.Double x, ReadAccessor.Double y, boolean[] ind, boolean na_fail) {
         complete1(n, ncx, x, ind, na_fail);
 
         for (int j = 0; j < ncy; j++) {
@@ -667,12 +672,12 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    static void find_na_1(int n, int ncx, double[] x, boolean[] has_na) {
+    static void find_na_1(int n, int ncx, ReadAccessor.Double x, boolean[] has_na) {
         for (int j = 0; j < ncx; j++) {
             int z = j * n;
             has_na[j] = false;
             for (int i = 0; i < n; i++) {
-                if (ISNAN(x[z + i])) {
+                if (ISNAN(x.getDataAt(z + i))) {
                     has_na[j] = true;
                     break;
                 }
@@ -680,7 +685,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         }
     }
 
-    static void find_na_2(int n, int ncx, int ncy, double[] x, double[] y, boolean[] has_na_x, boolean[] has_na_y) {
+    static void find_na_2(int n, int ncx, int ncy, ReadAccessor.Double x, ReadAccessor.Double y, boolean[] has_na_x, boolean[] has_na_y) {
         find_na_1(n, ncx, x, has_na_x);
         find_na_1(n, ncy, y, has_na_y);
     }
@@ -689,36 +694,36 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
      * co[vr](x, y, use = { 1, 2, 3, 4, 5 } "all.obs", "complete.obs", "pairwise.complete",
      * "everything", "na.or.complete" kendall = TRUE/FALSE)
      */
-    public RDoubleVector corcov(RDoubleVector x, RDoubleVector y, int method, boolean kendall) throws RError {
+    public RDoubleVector corcov(ReadAccessor.Double x, ReadAccessor.Double y, int method, boolean kendall) throws RError {
         int n, ncx, ncy;
 
         /* Arg.1: x */
-        if (isFactorX.executeIsFactor(x)) {
+        if (isFactorX.executeIsFactor(x.getVector())) {
             error("'x' is a factor");
             // maybe only warning: "Calling var(x) on a factor x is deprecated and will become an
             // error.\n Use something like 'all(duplicated(x)[-1L])' to test for a constant vector."
         }
         /* length check of x -- only if(empty_err) --> below */
-        int[] xDims = getDimsXNode.getDimensions(x);
+        int[] xDims = getDimsXNode.getDimensions(x.getVector());
         boolean ansmat = matrixProfile.profile(GetDimAttributeNode.isMatrix(xDims));
         if ((ansmat)) {
             n = xDims[0];
             ncx = xDims[1];
         } else {
-            n = x.getLength();
+            n = x.getVector().getLength();
             ncx = 1;
         }
         /* Arg.2: y */
         if (y == null) {/* y = x : var() */
             ncy = ncx;
         } else {
-            if (isFactorY.executeIsFactor(y)) {
+            if (isFactorY.executeIsFactor(y.getVector())) {
                 error("'y' is a factor");
                 // maybe only warning: "Calling var(x) on a factor x is deprecated and will become
                 // an error.\n Use something like 'all(duplicated(x)[-1L])' to test for a constant
                 // vector."
             }
-            int[] yDims = getDimsYNode.getDimensions(y);
+            int[] yDims = getDimsYNode.getDimensions(y.getVector());
             if (GetDimAttributeNode.isMatrix(yDims)) {
                 if (yDims[0] != n) {
                     error("incompatible dimensions");
@@ -726,7 +731,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 ncy = yDims[1];
                 ansmat = true;
             } else {
-                if (y.getLength() != n) {
+                if (y.getVector().getLength() != n) {
                     error("incompatible dimensions");
                 }
                 ncy = 1;
@@ -744,7 +749,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                 break;
             case 2: /* complete */
                 /* did na.omit in R */
-                if (x.getLength() == 0) {
+                if (x.getVector().getLength() == 0) {
                     error("no complete element pairs");
                 }
                 break;
@@ -761,15 +766,14 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
             default:
                 error("invalid 'use' (computational method)");
         }
-        if (empty_err && x.getLength() == 0) {
+        if (empty_err && x.getVector().getLength() == 0) {
             error("'x' is empty");
         }
 
-        double[] xData = x.getDataWithoutCopying();
         double[] ans = new double[ncx * ncy];
         boolean[] sd_0 = new boolean[1];
 
-        evaluate(y, kendall, isCor, n, ncx, ncy, na_fail, everything, empty_err, pair, xData, ans, sd_0);
+        evaluate(y, kendall, isCor, n, ncx, ncy, na_fail, everything, empty_err, pair, x, ans, sd_0);
 
         if (sd_0[0]) { /* only in cor() */
             warning(RError.Message.SD_ZERO);
@@ -787,7 +791,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
         if (ansmat) { /* set dimnames() when applicable */
             RList newDimNames = null;
             if (y == null) {
-                RList dimNames = getDimsNamesXNode.getDimNames(x);
+                RList dimNames = getDimsNamesXNode.getDimNames(x.getVector());
                 if (dimNames != null) {
                     Object names = dimNames.getDataAt(1);
                     if (names != RNull.instance) {
@@ -795,8 +799,8 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                     }
                 }
             } else {
-                RList dimNamesX = getDimsNamesXNode.getDimNames(x);
-                RList dimNamesY = getDimsNamesYNode.getDimNames(y);
+                RList dimNamesX = getDimsNamesXNode.getDimNames(x.getVector());
+                RList dimNamesY = getDimsNamesYNode.getDimNames(y.getVector());
                 Object namesX = dimNamesX.getLength() >= 2 ? dimNamesX.getDataAt(1) : RNull.instance;
                 Object namesY = dimNamesY.getLength() >= 2 ? dimNamesY.getDataAt(1) : RNull.instance;
                 if (namesX != RNull.instance || namesY != RNull.instance) {
@@ -814,19 +818,19 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
     }
 
     @TruffleBoundary
-    private static void evaluate(RDoubleVector y, boolean kendall, boolean cor, int n, int ncx, int ncy, boolean na_fail, boolean everything, boolean empty_err, boolean pair, double[] xData,
-                    double[] ans, boolean[] sd_0) {
+    private static void evaluate(ReadAccessor.Double y, boolean kendall, boolean cor, int n, int ncx, int ncy, boolean na_fail, boolean everything, boolean empty_err, boolean pair,
+                    ReadAccessor.Double x, double[] ans, boolean[] sd_0) {
         if (y == null) {
             if (everything) { /* NA's are propagated */
                 double[] xm = new double[ncx];
                 boolean[] ind = new boolean[ncx];
-                find_na_1(n, ncx, xData, /* --> has_na[] = */ ind);
-                cov_na_1(n, ncx, xData, xm, ind, ans, sd_0, cor, kendall);
+                find_na_1(n, ncx, x, /* --> has_na[] = */ ind);
+                cov_na_1(n, ncx, x, xm, ind, ans, sd_0, cor, kendall);
             } else if (!pair) { /* all | complete "var" */
                 double[] xm = new double[ncx];
                 boolean[] ind = new boolean[n];
-                complete1(n, ncx, xData, ind, na_fail);
-                cov_complete1(n, ncx, xData, xm, ind, ans, sd_0, cor, kendall);
+                complete1(n, ncx, x, ind, na_fail);
+                cov_complete1(n, ncx, x, xm, ind, ans, sd_0, cor, kendall);
                 if (empty_err) {
                     boolean indany = false;
                     for (int i = 0; i < n; i++) {
@@ -840,23 +844,22 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                     }
                 }
             } else { /* pairwise "var" */
-                cov_pairwise1(n, ncx, xData, ans, sd_0, cor, kendall);
+                cov_pairwise1(n, ncx, x, ans, sd_0, cor, kendall);
             }
         } else { /* Co[vr] (x, y) */
-            double[] yData = y.getDataWithoutCopying();
             if (everything) {
                 double[] xm = new double[ncx];
                 double[] ym = new double[ncy];
                 boolean[] ind = new boolean[ncx];
                 boolean[] has_na_y = new boolean[ncy];
-                find_na_2(n, ncx, ncy, xData, yData, ind, has_na_y);
-                cov_na_2(n, ncx, ncy, xData, yData, xm, ym, ind, has_na_y, ans, sd_0, cor, kendall);
+                find_na_2(n, ncx, ncy, x, y, ind, has_na_y);
+                cov_na_2(n, ncx, ncy, x, y, xm, ym, ind, has_na_y, ans, sd_0, cor, kendall);
             } else if (!pair) { /* all | complete */
                 double[] xm = new double[ncx];
                 double[] ym = new double[ncy];
                 boolean[] ind = new boolean[n];
-                complete2(n, ncx, ncy, xData, yData, ind, na_fail);
-                cov_complete2(n, ncx, ncy, xData, yData, xm, ym, ind, ans, sd_0, cor, kendall);
+                complete2(n, ncx, ncy, x, y, ind, na_fail);
+                cov_complete2(n, ncx, ncy, x, y, xm, ym, ind, ans, sd_0, cor, kendall);
                 if (empty_err) {
                     boolean indany = false;
                     for (int i = 0; i < n; i++) {
@@ -870,7 +873,7 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
                     }
                 }
             } else { /* pairwise */
-                cov_pairwise2(n, ncx, ncy, xData, yData, ans, sd_0, cor, kendall);
+                cov_pairwise2(n, ncx, ncy, x, y, ans, sd_0, cor, kendall);
             }
         }
     }
@@ -890,13 +893,16 @@ public abstract class Covcor extends RExternalBuiltinNode.Arg4 {
     }
 
     @Specialization
-    public Object call(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y, int method, boolean iskendall) {
-        return corcov(x.materialize(), null, method, iskendall);
+    public Object call(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y, int method, boolean iskendall,
+                    @Cached("create()") VectorReadAccess.Double vecReadAccess) {
+        return corcov(new ReadAccessor.Double(x, vecReadAccess), null, method, iskendall);
     }
 
     @Specialization
-    public Object call(RAbstractDoubleVector x, RAbstractDoubleVector y, int method, boolean iskendall) {
-        return corcov(x.materialize(), y.materialize(), method, iskendall);
+    public Object call(RAbstractDoubleVector x, RAbstractDoubleVector y, int method, boolean iskendall,
+                    @Cached("create()") VectorReadAccess.Double xReadAccess,
+                    @Cached("create()") VectorReadAccess.Double yReadAccess) {
+        return corcov(new ReadAccessor.Double(x, xReadAccess), new ReadAccessor.Double(y, yReadAccess), method, iskendall);
     }
 
     private final BranchProfile naInRes = BranchProfile.create();
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
index 4bb86b4814f961b6c24be2ff3d46766a7771ad2b..0a07a8b78c67ee7965a500d2cb61c1561e9feffc 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
@@ -20,7 +20,7 @@ import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 
 // translated from library/stats/src/hclust_utils.c
 
@@ -34,8 +34,8 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
 
     @Specialization
     protected RIntVector cutree(RAbstractIntVector merge, RAbstractIntVector which,
-                    @Cached("new()") AccessVector.Int mergeAccess,
-                    @Cached("new()") AccessVector.Int whichAccess,
+                    @Cached("create()") VectorReadAccess.Int mergeAccess,
+                    @Cached("create()") VectorReadAccess.Int whichAccess,
                     @Cached("create()") GetDimAttributeNode getDimNode) {
         int whichLen = which.getLength();
 
@@ -59,8 +59,8 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
         int[] z = new int[n];
 
         int[] iAns = new int[n * whichLen];
-        Object mergeStore = mergeAccess.init(merge);
-        Object whichStore = whichAccess.init(which);
+        Object mergeStore = mergeAccess.getDataStore(merge);
+        Object whichStore = whichAccess.getDataStore(which);
 
         // for (k = 1; k <= n; k++) {
         for (k = 0; k < n; k++) {
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
index b1b5b7c187e27f3f64ebfebeee367ecff6cf03a3..62883376e19d6cccdc6e3ab014c7765086f15e4e 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java
@@ -20,7 +20,8 @@ import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector;
+import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 
 public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
 
@@ -31,11 +32,12 @@ public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
 
     @Specialization
     protected RDoubleVector doubleCentre(RAbstractDoubleVector aVecAbs,
-                    @Cached("new()") AccessVector.Double aAccess,
+                    @Cached("create()") VectorReadAccess.Double aAccess,
+                    @Cached("create()") SetDataAt.Double aSetter,
                     @Cached("create()") GetDimAttributeNode getDimNode) {
         RDoubleVector aVec = aVecAbs.materialize();
         int n = getDimNode.nrows(aVec);
-        Object aStore = aAccess.init(aVec);
+        Object aStore = aAccess.getDataStore(aVec);
         for (int i = 0; i < n; i++) {
             double sum = 0;
             for (int j = 0; j < n; j++) {
@@ -44,7 +46,7 @@ public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
             sum /= n;
             for (int j = 0; j < n; j++) {
                 double val = aAccess.getDataAt(aVec, aStore, i + j * n);
-                aAccess.setDataAt(aVec, aStore, i + j * n, val - sum);
+                aSetter.setDataAt(aVec, aStore, i + j * n, val - sum);
             }
         }
         for (int j = 0; j < n; j++) {
@@ -55,7 +57,7 @@ public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
             sum /= n;
             for (int i = 0; i < n; i++) {
                 double val = aAccess.getDataAt(aVec, aStore, i + j * n);
-                aAccess.setDataAt(aVec, aStore, i + j * n, val - sum);
+                aSetter.setDataAt(aVec, aStore, i + j * n, val - sum);
             }
         }
         return aVec;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
index 8167a7610c109ba64237738c0739f3ef33bb9599..56fa2752f569d2701e8f2239d05775022b239357 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java
@@ -36,8 +36,9 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector.DoubleAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandomNumberProvider;
 import com.oracle.truffle.r.runtime.nmath.distr.RMultinom;
 import com.oracle.truffle.r.runtime.nmath.distr.Rbinom;
@@ -68,7 +69,8 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
 
     @Specialization
     protected RIntVector doMultinom(int n, int size, RAbstractDoubleVector probsVec,
-                    @Cached("new()") AccessVector.Double probsAccess,
+                    @Cached("create()") VectorReadAccess.Double probsAccess,
+                    @Cached("create()") SetDataAt.Double probsSetter,
                     @Cached("create()") ReuseNonSharedNode reuseNonSharedNode,
                     @Cached("createClassProfile()") ValueProfile randGeneratorClassProfile,
                     @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile,
@@ -76,12 +78,12 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
                     @Cached("createNames()") GetFixedAttributeNode getNamesNode,
                     @Cached("createDimNames()") SetFixedAttributeNode setDimNamesNode) {
         RDoubleVector nonSharedProbs = ((RAbstractDoubleVector) reuseNonSharedNode.execute(probsVec)).materialize();
-        DoubleAccessor probs = new DoubleAccessor(nonSharedProbs, probsAccess);
-        fixupProb(nonSharedProbs, probs.store, probsAccess);
+        ReadAccessor.Double probs = new ReadAccessor.Double(nonSharedProbs, probsAccess);
+        fixupProb(nonSharedProbs, probs, probsSetter);
 
         RRNG.getRNGState();
         RandomNumberProvider rand = new RandomNumberProvider(randGeneratorClassProfile.profile(RRNG.currentGenerator()), RRNG.currentNormKind());
-        int k = probs.vector.getLength();
+        int k = nonSharedProbs.getLength();
         int[] result = new int[k * n];
         boolean isComplete = true;
         for (int i = 0, ik = 0; i < n; i++, ik += k) {
@@ -100,12 +102,12 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
         return resultVec;
     }
 
-    private void fixupProb(RDoubleVector p, Object pStore, AccessVector.Double pAccess) {
+    private void fixupProb(RDoubleVector p, ReadAccessor.Double pAccess, SetDataAt.Double pSetter) {
         double sum = 0.0;
         int npos = 0;
         int pLength = p.getLength();
         for (int i = 0; i < pLength; i++) {
-            double prob = pAccess.getDataAt(p, pStore, i);
+            double prob = pAccess.getDataAt(i);
             if (!Double.isFinite(prob)) {
                 throw error(NA_IN_PROB_VECTOR);
             }
@@ -121,8 +123,8 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
             throw error(NO_POSITIVE_PROBABILITIES);
         }
         for (int i = 0; i < pLength; i++) {
-            double prob = pAccess.getDataAt(p, pStore, i);
-            pAccess.setDataAt(p, pStore, i, prob / sum);
+            double prob = pAccess.getDataAt(i);
+            pSetter.setDataAt(p, pAccess.getStore(), i, prob / sum);
         }
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
index ee14351e7b93cc44b31ab3ceb978d7c1fae92ecc..ebba5274acc538099ba8d71b3b7b69dfcbbbc888 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java
@@ -46,8 +46,8 @@ import com.oracle.truffle.r.runtime.data.RDouble;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector.DoubleAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function2_1;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function2_2;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function3_1;
@@ -376,8 +376,8 @@ public final class StatsFunctionsNodes {
 
         @Specialization
         protected RDoubleVector approx(RAbstractDoubleVector x, RAbstractDoubleVector y, RAbstractDoubleVector v, int method, double yl, double yr, double f,
-                                       @Cached("new()") AccessVector.Double xAccess,
-                                       @Cached("new()") AccessVector.Double yAccess) {
+                        @Cached("create()") VectorReadAccess.Double xAccess,
+                        @Cached("create()") VectorReadAccess.Double yAccess) {
             int nx = x.getLength();
             int nout = v.getLength();
             double[] yout = new double[nout];
@@ -390,8 +390,8 @@ public final class StatsFunctionsNodes {
             apprMeth.yhigh = yr;
             naCheck.enable(true);
 
-            DoubleAccessor xAccessor = new DoubleAccessor(x, xAccess);
-            DoubleAccessor yAccessor = new DoubleAccessor(y, yAccess);
+            ReadAccessor.Double xAccessor = new ReadAccessor.Double(x, xAccess);
+            ReadAccessor.Double yAccessor = new ReadAccessor.Double(y, yAccess);
             for (int i = 0; i < nout; i++) {
                 double xouti = v.getDataAt(i);
                 yout[i] = RRuntime.isNAorNaN(xouti) ? xouti : approx1(xouti, xAccessor, yAccessor, nx, apprMeth);
@@ -408,8 +408,8 @@ public final class StatsFunctionsNodes {
             int kind;
         }
 
-        private static double approx1(double v, DoubleAccessor x, DoubleAccessor y, int n,
-                                      ApprMeth apprMeth) {
+        private static double approx1(double v, ReadAccessor.Double x, ReadAccessor.Double y, int n,
+                        ApprMeth apprMeth) {
             /* Approximate y(v), given (x,y)[i], i = 0,..,n-1 */
             int i;
             int j;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
index 792abffb0e426b6d7920b2eb98ee7f5bc0f7064c..0a8f312ca49b9203ceeae75e9933d33601917edb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java
@@ -1005,7 +1005,7 @@ public abstract class ConnectionFunctions {
                 chars = new byte[1];
                 chars[0] = ((RRaw) vec).getRawDataAt(0);
             } else {
-                chars = ((RRawVector) vec).getDataWithoutCopying();
+                chars = ((RRawVector) vec).getReadonlyData();
             }
             strings.add(new String(chars, 0, n));
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CrossprodCommon.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CrossprodCommon.java
index 0b0041f6e72690ce43716b6a75d4daf6e94ccea0..e88dada037ba1aa458c38711edc7073277dca85c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CrossprodCommon.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CrossprodCommon.java
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.VectorToArray;
+import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
 
 /**
  * Implements the basic logic for {@code crossprod} and {@code tcrossprod}. Either the first matrix
@@ -102,7 +102,7 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 {
 
     @Specialization(guards = "x.isMatrix()")
     protected RDoubleVector crossprodDoubleMatrix(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y,
-                    @Cached("create()") VectorToArray vectorToArrayNode,
+                    @Cached("create()") GetReadonlyData.Double getReadonlyData,
                     @Cached("create()") GetDimAttributeNode getDimsNode,
                     @Cached("create()") GetDimAttributeNode getResultDimsNode) {
         int[] xDims = getDimsNode.getDimensions(x);
@@ -113,7 +113,7 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 {
         RDoubleVector result = mirror(
                         matMult.doubleMatrixMultiply(x, x, xRows, xCols, yRows, yCols, getXRowStride(xDims[0]), getXColStride(xDims[0]), getYRowStride(xDims[0]), getYColStride(xDims[0]), true),
                         getResultDimsNode,
-                        vectorToArrayNode);
+                        getReadonlyData);
         return copyDimNames(x, x, result);
     }
 
@@ -172,13 +172,13 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 {
         return result;
     }
 
-    private static RDoubleVector mirror(RDoubleVector result, GetDimAttributeNode getResultDimsNode, VectorToArray vectorToArrayNode) {
+    private static RDoubleVector mirror(RDoubleVector result, GetDimAttributeNode getResultDimsNode, GetReadonlyData.Double getReadonlyData) {
         // Mirroring the result is not only good for performance, but it is also required to produce
         // the same result as GNUR.
         int[] resultDims = getResultDimsNode.getDimensions(result);
         assert result.isMatrix() && resultDims[0] == resultDims[1];
         int size = resultDims[0];
-        double[] data = vectorToArrayNode.getReadonly(result);
+        double[] data = getReadonlyData.execute(result);
         for (int row = 0; row < size; row++) {
             int destIndex = row * size + row + 1;
             int sourceIndex = (row + 1) * size + row;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
index 2df8eb603794c158a712ea6ca84146946623c2cd..ea9010d63eb5986035bdaf2631fd9772d243f1c1 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
@@ -1103,10 +1103,11 @@ public class GrepFunctions {
                     RIntVector res;
                     if (pattern.length() == 0) {
                         String txt = vector.getDataAt(i);
-                        res = RDataFactory.createIntVector(txt.length());
+                        int[] resData = new int[txt.length()];
                         for (int j = 0; j < txt.length(); j++) {
-                            res.setDataAt(res.getInternalStore(), j, j + 1);
+                            resData[j] = j + 1;
                         }
+                        res = RDataFactory.createIntVector(resData, RDataFactory.COMPLETE_VECTOR);
                         setMatchLengthAttrNode.execute(res, RDataFactory.createIntVector(txt.length()));
                         if (useBytes) {
                             setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index 8902a830b06761acf78c1589a33f1bd759f088f9..ec52c0c7533860dff4b6feb8f2d488916781203a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -62,7 +62,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.VectorToArray;
+import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
 import com.oracle.truffle.r.runtime.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
@@ -321,8 +321,8 @@ public class LaFunctions {
 
         @Specialization
         protected RDoubleVector doQrCoefReal(RList qIn, RAbstractDoubleVector b,
-                        @Cached("create()") VectorToArray qrToArrayNode,
-                        @Cached("create()") VectorToArray tauToArrayNode,
+                        @Cached("create()") GetReadonlyData.Double qrToArrayNode,
+                        @Cached("create()") GetReadonlyData.Double tauToArrayNode,
                         @Cached("create()") GetDimAttributeNode getBDimsNode,
                         @Cached("create()") GetDimAttributeNode getQDimsNode,
                         @Cached("create()") LapackRFFI.DormqrNode dormqrNode,
@@ -341,8 +341,8 @@ public class LaFunctions {
             int nrhs = bDims[1];
             double[] work = new double[1];
             // qr and tau do not really need copying
-            double[] qrData = qrToArrayNode.getReadonly(qr);
-            double[] tauData = tauToArrayNode.getReadonly(tau);
+            double[] qrData = qrToArrayNode.execute(qr);
+            double[] tauData = tauToArrayNode.execute(tau);
             // this will be the result, we are going to modify this array
             double[] bData = b.materialize().getDataCopy();
             // ask for optimal size of work array
@@ -387,7 +387,7 @@ public class LaFunctions {
         @Specialization
 
         protected RList doDetGeReal(RAbstractDoubleVector aIn, boolean useLog,
-                        @Cached("create()") VectorToArray vectorToArrayNode,
+                        @Cached("create()") GetReadonlyData.Double vectorToArrayNode,
                         @Cached("create()") GetDimAttributeNode getDimsNode,
                         @Cached("create()") LapackRFFI.DgetrfNode dgetrfNode) {
             RDoubleVector a = (RDoubleVector) aIn.copy();
@@ -395,7 +395,7 @@ public class LaFunctions {
             int n = aDims[0];
             int[] ipiv = new int[n];
             double modulus = 0;
-            double[] aData = vectorToArrayNode.getReadonly(a);
+            double[] aData = vectorToArrayNode.execute(a);
             int info = dgetrfNode.execute(n, n, aData, n, ipiv);
             int sign = 1;
             if (info < 0) {
@@ -656,7 +656,10 @@ public class LaFunctions {
                     bData = bin.materialize().getDataNonShared();
                 } else {
                     bData = new double[n];
-                    System.arraycopy(bin.getInternalStore(), 0, bData, 0, n * p);
+                    // TODO: length for arraycopy is n*p, but bData is new double[n] ?? Should be
+                    // rewritten to manually copy using getDataAt, or using a new node in
+                    // c.o.t.r.runtime.data.nodes (the same in the "else" branch)
+                    System.arraycopy(bin.materialize().getReadonlyData(), 0, bData, 0, n * p);
                 }
                 b = RDataFactory.createDoubleVector(bData, RDataFactory.COMPLETE_VECTOR);
                 setBDimsNode.setDimensions(b, new int[]{n, p});
@@ -680,7 +683,7 @@ public class LaFunctions {
                     bData = bin.materialize().getDataNonShared();
                 } else {
                     bData = new double[n];
-                    System.arraycopy(bin.getInternalStore(), 0, bData, 0, n * p);
+                    System.arraycopy(bin.materialize().getReadonlyData(), 0, bData, 0, n * p);
                 }
                 b = RDataFactory.createDoubleVector(bData, RDataFactory.COMPLETE_VECTOR);
                 if (aDn != null) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
index bddcb8ae9ddcea89c572c7bd7d4363be1daf4b4c..53a2fe0007ca4e46b1486dddb6a8a4aa6dd8fd86 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatMult.java
@@ -58,7 +58,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.VectorToArray;
+import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
@@ -151,8 +151,8 @@ public abstract class MatMult extends RBuiltinNode.Arg2 {
     private final BranchProfile incompleteProfile = BranchProfile.create();
     @CompilationFinal private boolean seenLargeMatrix;
 
-    @Child private VectorToArray aToArrayNode = VectorToArray.create();
-    @Child private VectorToArray bToArrayNode = VectorToArray.create();
+    @Child private GetReadonlyData.Double aToArrayNode = GetReadonlyData.Double.create();
+    @Child private GetReadonlyData.Double bToArrayNode = GetReadonlyData.Double.create();
 
     private RDoubleVector doubleMatrixMultiply(RAbstractDoubleVector a, RAbstractDoubleVector b, int aRows, int aCols, int bRows, int bCols) {
         return doubleMatrixMultiply(a, b, aRows, aCols, bRows, bCols, 1, aRows, 1, bRows, false);
@@ -180,8 +180,8 @@ public abstract class MatMult extends RBuiltinNode.Arg2 {
         if (aCols != bRows) {
             throw error(RError.Message.NON_CONFORMABLE_ARGS);
         }
-        double[] dataA = aToArrayNode.getReadonly(a.materialize());
-        double[] dataB = bToArrayNode.getReadonly(b.materialize());
+        double[] dataA = aToArrayNode.execute(a.materialize());
+        double[] dataB = bToArrayNode.execute(b.materialize());
         double[] result = new double[aRows * bCols];
 
         if (!seenLargeMatrix && (aRows > BLOCK_SIZE || aCols > BLOCK_SIZE || bRows > BLOCK_SIZE || bCols > BLOCK_SIZE)) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
index c7f2e016619af2ea22b6d472d57d526a009824c9..d5a57d1dff52675799734456dd6fa29cbe0f0c50 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Merge.java
@@ -31,7 +31,7 @@ import com.oracle.truffle.r.runtime.data.RIntVector;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.nodes.VectorToArray;
+import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
 
 /**
  * Note: invoked from merge.data.frame.
@@ -82,8 +82,8 @@ public abstract class Merge extends RBuiltinNode.Arg4 {
 
     @Specialization
     RList merge(RAbstractIntVector xIndsAbstract, RAbstractIntVector yIndsAbstract, boolean allX, boolean allY,
-                    @Cached("create()") VectorToArray xIndsToArray,
-                    @Cached("create()") VectorToArray yIndsToArray) {
+                    @Cached("create()") GetReadonlyData.Int xIndsToArray,
+                    @Cached("create()") GetReadonlyData.Int yIndsToArray) {
         RIntVector xInds = xIndsAbstract.materialize();
         RIntVector yInds = yIndsAbstract.materialize();
 
@@ -98,8 +98,8 @@ public abstract class Merge extends RBuiltinNode.Arg4 {
         for (int i = 0; i < ny; i++) {
             iy[i] = i + 1;
         }
-        int[] xIndsData = xIndsToArray.getReadonly(xInds);
-        int[] yIndsData = yIndsToArray.getReadonly(yInds);
+        int[] xIndsData = xIndsToArray.execute(xInds);
+        int[] yIndsData = yIndsToArray.execute(yInds);
         isortWithIndex(xIndsData, ix, nx);
         isortWithIndex(yIndsData, iy, ny);
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
index 57d232e5c9617d276e19f65246073deb5ff2b49d..0a06e7de9416c1cc2199ea5d53cbaef02eaa601f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java
@@ -44,7 +44,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractListVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 
 /**
  * The {@code split} internal. Internal version of 'split' is invoked from 'split.default' function
@@ -64,7 +64,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @SuppressWarnings("unused") private final ConditionProfile noStringLevels = ConditionProfile.createBinaryProfile();
     private final ConditionProfile namesProfile = ConditionProfile.createBinaryProfile();
-    @Child private AccessVector.Int factorAccess = new AccessVector.Int();
+    @Child private VectorReadAccess.Int factorAccess = VectorReadAccess.Int.create();
 
     private static final int INITIAL_SIZE = 5;
     private static final int SCALE_FACTOR = 2;
@@ -75,7 +75,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractListVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.init(f);
+        Object fStore = factorAccess.getDataStore(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -89,7 +89,8 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         // perform split
         int factorLen = f.getLength();
         for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based int vector
+            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
+                                                                         // int vector
             Object[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -109,7 +110,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractIntVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.init(f);
+        Object fStore = factorAccess.getDataStore(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -123,7 +124,8 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         // perform split
         int factorLen = f.getLength();
         for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based int vector
+            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
+                                                                         // int vector
             int[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -143,7 +145,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractDoubleVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.init(f);
+        Object fStore = factorAccess.getDataStore(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -157,7 +159,8 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         // perform split
         int factorLen = f.getLength();
         for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based int vector
+            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
+                                                                         // int vector
             double[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -177,7 +180,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractStringVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.init(f);
+        Object fStore = factorAccess.getDataStore(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -191,7 +194,8 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         // perform split
         int factorLen = f.getLength();
         for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based int vector
+            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
+                                                                         // int vector
             String[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -211,7 +215,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractLogicalVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.init(f);
+        Object fStore = factorAccess.getDataStore(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -225,7 +229,8 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         // perform split
         int factorLen = f.getLength();
         for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based int vector
+            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
+                                                                         // int vector
             byte[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -245,7 +250,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RRawVector x, RAbstractIntVector f) {
-        Object fStore = factorAccess.init(f);
+        Object fStore = factorAccess.getDataStore(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -259,7 +264,8 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         // perform split
         int factorLen = f.getLength();
         for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based int vector
+            int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based
+                                                                         // int vector
             byte[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -287,7 +293,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
             }
             int factorLen = factor.getLength();
             for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) {
-                int resultIndex = factorAccess.getDataAt(factor, fStore, fi) - 1; // a factor is a 1-based int vector
+                int resultIndex = factorAccess.getDataAt(factor, fStore, fi) - 1; // a factor is a
+                                                                                  // 1-based int
+                                                                                  // vector
                 namesArr[resultIndex][resultNamesIdxs[resultIndex]++] = xNames.getDataAt(i);
             }
             RStringVector[] resultNames = new RStringVector[nLevels];
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
index aa0cd2a7d0bd8017a4615264e7c6ba9686a6b60c..24a3fbadbbe1f1fbfdcc1f0263c56b1207f9df30 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sum.java
@@ -42,7 +42,7 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.builtins.RBuiltin;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.nodes.VectorToArray;
+import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData;
 import com.oracle.truffle.r.runtime.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
@@ -75,7 +75,7 @@ public abstract class Sum extends RBuiltinNode.Arg2 {
 
     @Specialization(guards = {"FULL_PRECISION", "args.getLength() == 1", "isRDoubleVector(args.getArgument(0))", "naRm == cachedNaRm"})
     protected double sumLengthOneRDoubleVector(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm,
-                    @Cached("create()") VectorToArray vectorToArrayNode,
+                    @Cached("create()") GetReadonlyData.Double vectorToArrayNode,
                     @Cached("naRm") boolean cachedNaRm,
                     @Cached("create()") VectorLengthProfile lengthProfile,
                     @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
@@ -86,7 +86,7 @@ public abstract class Sum extends RBuiltinNode.Arg2 {
         int length = lengthProfile.profile(vector.getLength());
 
         if (needsExactSumProfile.profile(length >= 3)) {
-            return exactSumNode.execute(vectorToArrayNode.getReadonly(vector), !vector.isComplete(), cachedNaRm);
+            return exactSumNode.execute(vectorToArrayNode.execute(vector), !vector.isComplete(), cachedNaRm);
         } else {
             na.enable(vector);
             loopProfile.profileCounted(length);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
index 6bfbaee4764141396cf2a3c124e30af2bb92d6ab..b61abc3dc009fa760ff99ca77b3bcb47ffc58f11 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java
@@ -19,6 +19,7 @@ import java.util.function.BiFunction;
 import java.util.function.Function;
 
 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.profiles.BranchProfile;
@@ -53,6 +54,8 @@ 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.data.nodes.SetDataAt;
+import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @RBuiltin(name = "t.default", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE)
@@ -117,7 +120,7 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
         return r;
     }
 
-    protected RVector<?> transposeSquareMatrixInPlace(RVector<?> vector, Swap swapper) {
+    protected RVector<?> transposeSquareMatrixInPlace(RVector<?> vector, Object store, VectorReadAccess readAccess, SetDataAt setter, Swap swap) {
         int length = lengthProfile.profile(vector.getLength());
         assert vector.isMatrix();
         int[] dims = getDimensions(vector);
@@ -129,7 +132,16 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
         loopProfile.profileCounted(length);
         for (int i = 0; loopProfile.inject(i < dim); i++) {
             for (int j = 0; j < i; j++) {
-                swapper.swap(i * dim + j, j * dim + i);
+                int swapi = i * dim + j;
+                int swapj = j * dim + i;
+                if (swap != null) {
+                    swap.swap(swapi, swapj);
+                } else {
+                    Object tmp = readAccess.getDataAtAsObject(vector, store, swapi);
+                    Object jVal = readAccess.getDataAtAsObject(vector, store, swapj);
+                    setter.setDataAtAsObject(vector, store, swapi, jVal);
+                    setter.setDataAtAsObject(vector, store, swapj, tmp);
+                }
             }
         }
         // don't need to set new dimensions; it is a square matrix
@@ -156,68 +168,55 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
     }
 
     @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractIntVector x) {
+    protected RVector<?> transposeSquare(RAbstractIntVector x,
+                    @Cached("create()") VectorReadAccess.Int readAccess,
+                    @Cached("create()") SetDataAt.Int setter) {
         RIntVector reused = (RIntVector) reuseNonShared.execute(x).materialize();
-        int[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, (i, j) -> {
-            int tmp = store[i];
-            store[i] = store[j];
-            store[j] = tmp;
-        });
+        Object reusedStore = readAccess.getDataStore(reused);
+        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
     }
 
     @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractLogicalVector x) {
+    protected RVector<?> transposeSquare(RAbstractLogicalVector x,
+                    @Cached("create()") VectorReadAccess.Logical readAccess,
+                    @Cached("create()") SetDataAt.Logical setter) {
         RLogicalVector reused = (RLogicalVector) reuseNonShared.execute(x).materialize();
-        byte[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, (i, j) -> {
-            byte tmp = store[i];
-            store[i] = store[j];
-            store[j] = tmp;
-        });
+        Object reusedStore = readAccess.getDataStore(reused);
+        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
     }
 
     @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractDoubleVector x) {
+    protected RVector<?> transposeSquare(RAbstractDoubleVector x,
+                    @Cached("create()") VectorReadAccess.Double readAccess,
+                    @Cached("create()") SetDataAt.Double setter) {
         RDoubleVector reused = (RDoubleVector) reuseNonShared.execute(x).materialize();
-        double[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, (i, j) -> {
-            double tmp = store[i];
-            store[i] = store[j];
-            store[j] = tmp;
-        });
+        Object reusedStore = readAccess.getDataStore(reused);
+        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
     }
 
     @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractComplexVector x) {
+    protected RVector<?> transposeSquare(RAbstractComplexVector x,
+                    @Cached("create()") VectorReadAccess.Complex readAccess,
+                    @Cached("create()") SetDataAt.Complex setter) {
         RComplexVector reused = (RComplexVector) reuseNonShared.execute(x).materialize();
-        double[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, (i, j) -> {
-            double tmpReal = store[i * 2];
-            double tmpImg = store[i * 2 + 1];
-            store[i * 2] = store[j * 2];
-            store[i * 2 + 1] = store[j * 2 + 1];
-            store[j * 2] = tmpReal;
-            store[j * 2 + 1] = tmpImg;
-        });
+        Object reusedStore = readAccess.getDataStore(reused);
+        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
     }
 
     @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractStringVector x) {
+    protected RVector<?> transposeSquare(RAbstractStringVector x,
+                    @Cached("create()") VectorReadAccess.String readAccess,
+                    @Cached("create()") SetDataAt.String setter) {
         RStringVector reused = (RStringVector) reuseNonShared.execute(x).materialize();
-        String[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, (i, j) -> {
-            String tmp = store[i];
-            store[i] = store[j];
-            store[j] = tmp;
-        });
+        Object reusedStore = readAccess.getDataStore(reused);
+        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
     }
 
     @Specialization(guards = "isSquare(x)")
     protected RVector<?> transposeSquare(RAbstractListVector x) {
         RList reused = (RList) reuseNonShared.execute(x).materialize();
         Object[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, (i, j) -> {
+        return transposeSquareMatrixInPlace(reused, store, null, null, (i, j) -> {
             Object tmp = store[i];
             store[i] = store[j];
             store[j] = tmp;
@@ -225,14 +224,12 @@ public abstract class Transpose extends RBuiltinNode.Arg1 {
     }
 
     @Specialization(guards = "isSquare(x)")
-    protected RVector<?> transposeSquare(RAbstractRawVector x) {
+    protected RVector<?> transposeSquare(RAbstractRawVector x,
+                    @Cached("create()") VectorReadAccess.Raw readAccess,
+                    @Cached("create()") SetDataAt.Raw setter) {
         RRawVector reused = (RRawVector) reuseNonShared.execute(x).materialize();
-        byte[] store = reused.getDataWithoutCopying();
-        return transposeSquareMatrixInPlace(reused, (i, j) -> {
-            byte tmp = store[i];
-            store[i] = store[j];
-            store[j] = tmp;
-        });
+        Object reusedStore = readAccess.getDataStore(reused);
+        return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null);
     }
 
     @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"})
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 aefbeedf3e0ca1f840edfbf0eaa134e4b822aeb8..333012b0465d59c88387d85c3d73870e222fea8b 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
@@ -281,10 +281,13 @@ public final class ValuePrinterNode extends RBaseNode {
                 if (keys != null) {
                     int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, keys);
                     RAbstractStringVector abstractNames = new RStringWrapper(size, keys);
-                    RStringVector names = RDataFactory.createStringVector(size);
+                    String[] namesData = new String[size];
+                    boolean namesComplete = true;
                     for (int i = 0; i < size; i++) {
-                        names.setDataAt(names.getInternalStore(), i, abstractNames.getDataAt(i));
+                        namesData[i] = abstractNames.getDataAt(i);
+                        namesComplete &= RRuntime.isNA(namesData[i]);
                     }
+                    RStringVector names = RDataFactory.createStringVector(namesData, namesComplete);
 
                     return new RListWrapper(size, names);
                 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java
index 2549c6cfcd58ec8fcb06268d4e0fc7d932070d14..46379181eabac9abea35743bbf59a1aba13a8ed6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/PositionCheckSubsetNode.java
@@ -40,6 +40,7 @@ import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.Utils;
 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.RMissing;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -143,14 +144,7 @@ abstract class PositionCheckSubsetNode extends PositionCheckNode {
                     @Cached("createCountingProfile()") LoopConditionProfile lengthProfile,
                     @Cached("create()") GetNamesAttributeNode getNamesNode,
                     @Cached("create()") SetNamesAttributeNode setNamesNode) {
-        RAbstractIntVector intPosition = RDataFactory.createIntVector(positionLength);
-        // requires names preservation
-        RStringVector names = hasNamesProfile.profile(getNamesNode.getNames(position));
-        if (names != null) {
-            setNamesNode.setNames(intPosition, names);
-        }
-        Object convertedStore = intPosition.getInternalStore();
-
+        int[] intPosition = new int[positionLength];
         positionNACheck.enable(position);
         boolean hasSeenPositive = false;
         boolean hasSeenNegative = false;
@@ -201,10 +195,17 @@ abstract class PositionCheckSubsetNode extends PositionCheckNode {
                     intPositionValue--;
                 }
             }
-            intPosition.setDataAt(convertedStore, i, intPositionValue);
+            intPosition[i] = intPositionValue;
         }
-        intPosition.setComplete(!hasSeenNA);
-        return doIntegerProfiled(profile, dimensionLength, intPosition, positionLength, hasSeenPositive, hasSeenNegative, hasSeenNA, outOfBoundsCount, zeroCount, maxOutOfBoundsIndex);
+
+        RIntVector intPositionVec = RDataFactory.createIntVector(intPosition, !hasSeenNA);
+        // requires names preservation
+        RStringVector names = hasNamesProfile.profile(getNamesNode.getNames(position));
+        if (names != null) {
+            setNamesNode.setNames(intPositionVec, names);
+        }
+
+        return doIntegerProfiled(profile, dimensionLength, intPositionVec, positionLength, hasSeenPositive, hasSeenNegative, hasSeenNA, outOfBoundsCount, zeroCount, maxOutOfBoundsIndex);
 
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/SearchFirstStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/SearchFirstStringNode.java
index b1baf683b5031c769d903b4ef3db0054f8a93623..e197f4dd5edee1ff5ac5b11dd5005f195e77c9d6 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/SearchFirstStringNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/SearchFirstStringNode.java
@@ -110,7 +110,7 @@ final class SearchFirstStringNode extends Node {
         if (exactMatch) {
             RAbstractIntVector genericResult = searchGeneric(target, targetLength, elements, elementsLength, -1, true, names);
             if (genericResult != null) {
-                return (int[]) genericResult.getInternalStore();
+                return genericResult.materialize().getReadonlyData();
             }
         }
         return null;
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 aa5ab4daaf5c8e4ea9176bbdeaaf1fbdddedceca..523657c9364ad595ffec583557e2deecb119016f 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
@@ -614,6 +614,12 @@ public final class SpecialAttributesFunctions {
             return GetDimAttributeNodeGen.create();
         }
 
+        // TODO: getDimensions returns a naked array, which is in many places used to create a fresh
+        // vector ignoring the reference counting. This should really return a vector and the users
+        // should increment its ref-count if they want to put it into other
+        // attributes/list/environment/... This way, we wouldn't need to call getReadonlyData, which
+        // may copy the contents.
+
         public final int[] getDimensions(Object x) {
             // Let's handle the following two types directly so as to avoid wrapping and unwrapping
             // RIntVector. The getContainerDims spec would be invoked otherwise.
@@ -626,7 +632,7 @@ public final class SpecialAttributesFunctions {
                 return ((RPairList) x).getDimensions();
             }
             RIntVector dims = (RIntVector) execute(x);
-            return nullDimsProfile.profile(dims == null) ? null : dims.getInternalStore();
+            return nullDimsProfile.profile(dims == null) ? null : dims.getReadonlyData();
         }
 
         public static boolean isArray(int[] dimensions) {
@@ -637,6 +643,14 @@ public final class SpecialAttributesFunctions {
             return dimensions != null && dimensions.length == 2;
         }
 
+        public static boolean isArray(RIntVector dimensions) {
+            return dimensions != null && dimensions.getLength() > 0;
+        }
+
+        public static boolean isMatrix(RIntVector dimensions) {
+            return dimensions != null && dimensions.getLength() == 2;
+        }
+
         public final boolean isArray(RAbstractVector vector) {
             RIntVector dims = (RIntVector) execute(vector);
             return nullDimsProfile.profile(dims == null) ? false : dims.getLength() > 0;
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ImplicitClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ImplicitClassHierarchyNode.java
index 11da7440437b0245aadd3e2767eeffd3be4f1359..728001f28b60517afa6e788f0beb03949cbb56c4 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ImplicitClassHierarchyNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ImplicitClassHierarchyNode.java
@@ -138,10 +138,9 @@ public abstract class ImplicitClassHierarchyNode extends UnaryNode {
             RAttributable attributable = (RAttributable) value;
             RIntVector dim = (RIntVector) attributable.getAttr(RRuntime.DIM_ATTR_KEY);
             if (dim != null) {
-                int[] dimArray = dim.getInternalStore();
-                if (GetDimAttributeNode.isMatrix(dimArray)) {
+                if (GetDimAttributeNode.isMatrix(dim)) {
                     return implicitMatrixClass;
-                } else if (GetDimAttributeNode.isArray(dimArray)) {
+                } else if (GetDimAttributeNode.isArray(dim)) {
                     return implicitArrayClass;
                 }
             }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
index 164d40610dfc4da9704996e4c9fdb816c29071a2..a77f74f63d9ab98891b5b20991a0594958294612 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java
@@ -23,6 +23,7 @@
 package com.oracle.truffle.r.nodes.primitive;
 
 import com.oracle.truffle.api.dsl.Cached;
+import com.oracle.truffle.api.dsl.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.api.profiles.LoopConditionProfile;
@@ -36,7 +37,6 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RType;
-import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.RScalarVector;
@@ -49,6 +49,9 @@ 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.data.nodes.GetDataStore;
+import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
+import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 /**
@@ -251,16 +254,15 @@ public final class BinaryMapNode extends RBaseNode {
         }
         if (target == null) {
             int maxLength = maxLengthProfile.profile(leftLength >= rightLength) ? leftLength : rightLength;
-            target = createOrShareVector(leftLength, left, rightLength, right, maxLength);
-            Object store = target.getInternalStore();
+            RVector<?> targetVec = createOrShareVector(leftLength, left, rightLength, right, maxLength);
+            target = targetVec;
 
             assert left.getLength() == leftLength;
             assert right.getLength() == rightLength;
             assert leftCast.getRType() == argumentType;
             assert rightCast.getRType() == argumentType;
-            assert isStoreCompatible(store, resultType, leftLength, rightLength);
 
-            vectorNode.execute(function, store, leftCast, leftLength, rightCast, rightLength);
+            vectorNode.execute(function, targetVec, leftCast, leftLength, rightCast, rightLength);
             RBaseNode.reportWork(this, maxLength);
             target.setComplete(function.isComplete());
         }
@@ -270,111 +272,60 @@ public final class BinaryMapNode extends RBaseNode {
         return target;
     }
 
-    private RAbstractVector createOrShareVector(int leftLength, RAbstractVector left, int rightLength, RAbstractVector right, int maxLength) {
-        if (mayShareLeft && left.getRType() == resultType && shareLeft.profile(leftLength == maxLength && ((RShareable) left).isTemporary())) {
-            return left;
+    private RVector<?> createOrShareVector(int leftLength, RAbstractVector left, int rightLength, RAbstractVector right, int maxLength) {
+        if (mayShareLeft && left.getRType() == resultType && shareLeft.profile(leftLength == maxLength && ((RShareable) left).isTemporary()) && left instanceof RVector<?>) {
+            return (RVector<?>) left;
         }
-        if (mayShareRight && right.getRType() == resultType && shareRight.profile(rightLength == maxLength && ((RShareable) right).isTemporary())) {
-            return right;
+        if (mayShareRight && right.getRType() == resultType && shareRight.profile(rightLength == maxLength && ((RShareable) right).isTemporary()) && right instanceof RVector<?>) {
+            return (RVector<?>) right;
         }
         return resultType.create(maxLength, false);
     }
 
-    private static boolean isStoreCompatible(Object store, RType resultType, int leftLength, int rightLength) {
-        int maxLength = Math.max(leftLength, rightLength);
-        switch (resultType) {
-            case Raw:
-                assert store instanceof byte[] && ((byte[]) store).length == maxLength;
-                return true;
-            case Logical:
-                assert store instanceof byte[] && ((byte[]) store).length == maxLength;
-                return true;
-            case Integer:
-                assert store instanceof int[] && ((int[]) store).length == maxLength;
-                return true;
-            case Double:
-                assert store instanceof double[] && ((double[]) store).length == maxLength;
-                return true;
-            case Complex:
-                assert store instanceof double[] && ((double[]) store).length >> 1 == maxLength;
-                return true;
-            case Character:
-                assert store instanceof String[] && ((String[]) store).length == maxLength;
-                return true;
-            default:
-                throw RInternalError.shouldNotReachHere();
-        }
-    }
-
+    @ImportStatic(Utils.class)
     protected abstract static class VectorMapBinaryInternalNode extends RBaseNode {
 
-        private static final MapBinaryIndexedAction<byte[], RAbstractLogicalVector> LOGICAL_LOGICAL = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyLogical(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-        private static final MapBinaryIndexedAction<byte[], RAbstractIntVector> LOGICAL_INTEGER = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyLogical(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-        private static final MapBinaryIndexedAction<byte[], RAbstractDoubleVector> LOGICAL_DOUBLE = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyLogical(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-        private static final MapBinaryIndexedAction<byte[], RAbstractComplexVector> LOGICAL_COMPLEX = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyLogical(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-        private static final MapBinaryIndexedAction<byte[], RAbstractStringVector> LOGICAL_CHARACTER = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyLogical(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-        private static final MapBinaryIndexedAction<byte[], RAbstractRawVector> LOGICAL_RAW = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyLogical(RRuntime.raw2int(left.getRawDataAt(leftIndex)), RRuntime.raw2int(right.getRawDataAt(rightIndex)));
-                        };
-        private static final MapBinaryIndexedAction<byte[], RAbstractRawVector> RAW_RAW = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyRaw(left.getRawDataAt(leftIndex), right.getRawDataAt(rightIndex));
-                        };
-
-        private static final MapBinaryIndexedAction<int[], RAbstractIntVector> INTEGER_INTEGER = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyInteger(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-
-        private static final MapBinaryIndexedAction<double[], RAbstractIntVector> DOUBLE_INTEGER = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyDouble(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-
-        private static final MapBinaryIndexedAction<double[], RAbstractDoubleVector> DOUBLE = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyDouble(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-
-        private static final MapBinaryIndexedAction<double[], RAbstractComplexVector> COMPLEX = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            RComplex value = arithmetic.applyComplex(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                            result[resultIndex << 1] = value.getRealPart();
-                            result[(resultIndex << 1) + 1] = value.getImaginaryPart();
-                        };
-        private static final MapBinaryIndexedAction<String[], RAbstractStringVector> CHARACTER = //
-                        (arithmetic, result, resultIndex, left, leftIndex, right, rightIndex) -> {
-                            result[resultIndex] = arithmetic.applyCharacter(left.getDataAt(leftIndex), right.getDataAt(rightIndex));
-                        };
-
-        private final MapBinaryIndexedAction<Object, RAbstractVector> indexedAction;
+        private static final MapBinaryIndexedAction<Byte> LOGICAL_LOGICAL = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<Integer> LOGICAL_INTEGER = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<Double> LOGICAL_DOUBLE = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<RComplex> LOGICAL_COMPLEX = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<String> LOGICAL_CHARACTER = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<Byte> LOGICAL_RAW = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(RRuntime.raw2int(leftVal), RRuntime.raw2int(rightVal));
+        private static final MapBinaryIndexedAction<Byte> RAW_RAW = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyRaw(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<Integer> INTEGER_INTEGER = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyInteger(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<Integer> DOUBLE_INTEGER = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyDouble(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<Double> DOUBLE = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyDouble(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<RComplex> COMPLEX = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyComplex(leftVal, rightVal);
+        private static final MapBinaryIndexedAction<String> CHARACTER = //
+                        (arithmetic, leftVal, rightVal) -> arithmetic.applyCharacter(leftVal, rightVal);
+
+        private final MapBinaryIndexedAction<Object> indexedAction;
+
+        @Child private GetDataStore getTargetDataStore = GetDataStore.create();
+        @Child private SetDataAt targetSetDataAt;
 
         @SuppressWarnings("unchecked")
         protected VectorMapBinaryInternalNode(RType resultType, RType argumentType) {
-            this.indexedAction = (MapBinaryIndexedAction<Object, RAbstractVector>) createIndexedAction(resultType, argumentType);
+            this.indexedAction = (MapBinaryIndexedAction<Object>) createIndexedAction(resultType, argumentType);
+            this.targetSetDataAt = Utils.createSetDataAtNode(resultType);
         }
 
         public static VectorMapBinaryInternalNode create(RType resultType, RType argumentType) {
             return VectorMapBinaryInternalNodeGen.create(resultType, argumentType);
         }
 
-        private static MapBinaryIndexedAction<? extends Object, ? extends RAbstractVector> createIndexedAction(RType resultType, RType argumentType) {
+        private static MapBinaryIndexedAction<?> createIndexedAction(RType resultType, RType argumentType) {
             switch (resultType) {
                 case Raw:
                     assert argumentType == RType.Raw;
@@ -419,41 +370,66 @@ public final class BinaryMapNode extends RBaseNode {
             }
         }
 
-        public abstract void execute(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength);
+        public abstract void execute(BinaryMapFunctionNode node, RVector<?> store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength);
 
         @Specialization(guards = {"leftLength == 1", "rightLength == 1"})
         @SuppressWarnings("unused")
-        protected void doScalarScalar(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength) {
-            indexedAction.perform(node, store, 0, left, 0, right, 0);
+        protected void doScalarScalar(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
+                        @Cached("createIterator()") VectorIterator.Generic rightIterator) {
+            Object itLeft = leftIterator.init(left);
+            Object itRight = rightIterator.init(right);
+            Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
+            targetSetDataAt.setDataAtAsObject(result, getTargetDataStore.execute(result), 0, value);
         }
 
         @Specialization(replaces = "doScalarScalar", guards = {"leftLength == 1"})
         @SuppressWarnings("unused")
-        protected void doScalarVector(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+        protected void doScalarVector(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
+                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
                         @Cached("createCountingProfile()") LoopConditionProfile profile) {
             profile.profileCounted(rightLength);
+            Object itLeft = leftIterator.init(left);
+            Object itRight = rightIterator.init(right);
+            Object resultStore = getTargetDataStore.execute(result);
+            Object leftValue = leftIterator.next(left, itLeft);
             for (int i = 0; profile.inject(i < rightLength); ++i) {
-                indexedAction.perform(node, store, i, left, 0, right, i);
+                Object value = indexedAction.perform(node, leftValue, rightIterator.next(right, itRight));
+                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
             }
         }
 
         @Specialization(replaces = "doScalarScalar", guards = {"rightLength == 1"})
         @SuppressWarnings("unused")
-        protected void doVectorScalar(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+        protected void doVectorScalar(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
+                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
                         @Cached("createCountingProfile()") LoopConditionProfile profile) {
             profile.profileCounted(leftLength);
+            Object itLeft = leftIterator.init(left);
+            Object itRight = rightIterator.init(right);
+            Object resultStore = getTargetDataStore.execute(result);
+            Object rightValue = rightIterator.next(right, itRight);
             for (int i = 0; profile.inject(i < leftLength); ++i) {
-                indexedAction.perform(node, store, i, left, i, right, 0);
+                Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightValue);
+                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
             }
         }
 
         @Specialization(guards = {"leftLength == rightLength"})
         @SuppressWarnings("unused")
-        protected void doSameLength(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+        protected void doSameLength(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
+                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
                         @Cached("createCountingProfile()") LoopConditionProfile profile) {
             profile.profileCounted(leftLength);
+            Object itLeft = leftIterator.init(left);
+            Object itRight = rightIterator.init(right);
+            Object resultStore = getTargetDataStore.execute(result);
             for (int i = 0; profile.inject(i < leftLength); ++i) {
-                indexedAction.perform(node, store, i, left, i, right, i);
+                Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
+                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
             }
         }
 
@@ -462,30 +438,42 @@ public final class BinaryMapNode extends RBaseNode {
         }
 
         @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(leftLength, rightLength)"})
-        protected void doMultiplesLeft(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+        protected void doMultiplesLeft(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+                        @Cached("createIteratorWrapAround()") VectorIterator.Generic leftIterator,
+                        @Cached("createIterator()") VectorIterator.Generic rightIterator,
                         @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
                         @Cached("createCountingProfile()") LoopConditionProfile rightProfile) {
             int j = 0;
             rightProfile.profileCounted(rightLength / leftLength);
+            Object itLeft = leftIterator.init(left);
+            Object itRight = rightIterator.init(right);
+            Object resultStore = getTargetDataStore.execute(result);
             while (rightProfile.inject(j < rightLength)) {
                 leftProfile.profileCounted(leftLength);
                 for (int k = 0; leftProfile.inject(k < leftLength); k++) {
-                    indexedAction.perform(node, store, j, left, k, right, j);
+                    Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
+                    targetSetDataAt.setDataAtAsObject(result, resultStore, j, value);
                     j++;
                 }
             }
         }
 
         @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(rightLength, leftLength)"})
-        protected void doMultiplesRight(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+        protected void doMultiplesRight(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+                        @Cached("createIterator()") VectorIterator.Generic leftIterator,
+                        @Cached("createIteratorWrapAround()") VectorIterator.Generic rightIterator,
                         @Cached("createCountingProfile()") LoopConditionProfile leftProfile,
                         @Cached("createCountingProfile()") LoopConditionProfile rightProfile) {
             int j = 0;
             leftProfile.profileCounted(leftLength / rightLength);
+            Object itLeft = leftIterator.init(left);
+            Object itRight = rightIterator.init(right);
+            Object resultStore = getTargetDataStore.execute(result);
             while (leftProfile.inject(j < leftLength)) {
                 rightProfile.profileCounted(rightLength);
                 for (int k = 0; rightProfile.inject(k < rightLength); k++) {
-                    indexedAction.perform(node, store, j, left, j, right, k);
+                    Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
+                    targetSetDataAt.setDataAtAsObject(result, resultStore, j, value);
                     j++;
                 }
             }
@@ -505,26 +493,26 @@ public final class BinaryMapNode extends RBaseNode {
         }
 
         @Specialization(guards = {"!multiples(leftLength, rightLength)"})
-        protected void doNoMultiples(BinaryMapFunctionNode node, Object store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+        protected void doNoMultiples(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength,
+                        @Cached("createIteratorWrapAround()") VectorIterator.Generic leftIterator,
+                        @Cached("createIteratorWrapAround()") VectorIterator.Generic rightIterator,
                         @Cached("createCountingProfile()") LoopConditionProfile profile,
                         @Cached("createBinaryProfile()") ConditionProfile leftIncModProfile,
                         @Cached("createBinaryProfile()") ConditionProfile rightIncModProfile) {
-            int j = 0;
-            int k = 0;
             int max = Math.max(leftLength, rightLength);
             profile.profileCounted(max);
+            Object itLeft = leftIterator.init(left);
+            Object itRight = rightIterator.init(right);
+            Object resultStore = getTargetDataStore.execute(result);
             for (int i = 0; profile.inject(i < max); ++i) {
-                indexedAction.perform(node, store, i, left, j, right, k);
-                j = Utils.incMod(j, leftLength, leftIncModProfile);
-                k = Utils.incMod(k, rightLength, rightIncModProfile);
+                Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight));
+                targetSetDataAt.setDataAtAsObject(result, resultStore, i, value);
             }
             RError.warning(this, RError.Message.LENGTH_NOT_MULTI);
         }
 
-        private interface MapBinaryIndexedAction<A, V extends RAbstractVector> {
-
-            void perform(BinaryMapFunctionNode action, A store, int resultIndex, V left, int leftIndex, V right, int rightIndex);
-
+        private interface MapBinaryIndexedAction<V> {
+            Object perform(BinaryMapFunctionNode action, V left, V right);
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
index b901cd67808a18a7865db0696168a7a7a45221b9..aaa72efdec80a239329d21e901f04e54825e7a27 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java
@@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.primitive;
 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.ImportStatic;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
@@ -46,8 +47,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.GetDataStore;
+import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
+import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 public final class UnaryMapNode extends RBaseNode {
@@ -150,9 +153,9 @@ public final class UnaryMapNode extends RBaseNode {
             target = scalarNode.tryFoldConstantTime(operandCast, operandLength);
         }
         if (target == null) {
-            target = createOrShareVector(operandLength, operand);
-            Object store = target.getInternalStore();
-            vectorNode.apply(scalarNode, store, operandCast, operandLength);
+            RVector<?> targetVec = createOrShareVector(operandLength, operand);
+            target = targetVec;
+            vectorNode.apply(scalarNode, targetVec, operandCast, operandLength);
             RBaseNode.reportWork(this, operandLength);
             target.setComplete(scalarNode.isComplete());
         }
@@ -162,10 +165,10 @@ public final class UnaryMapNode extends RBaseNode {
         return target;
     }
 
-    private RAbstractVector createOrShareVector(int operandLength, RAbstractVector operand) {
+    private RVector<?> createOrShareVector(int operandLength, RAbstractVector operand) {
         RType resultType = getResultType();
-        if (mayShareOperand && operand.getRType() == resultType && shareOperand.profile(((RShareable) operand).isTemporary())) {
-            return operand;
+        if (mayShareOperand && operand.getRType() == resultType && shareOperand.profile(((RShareable) operand).isTemporary()) && operand instanceof RVector<?>) {
+            return (RVector<?>) operand;
         }
         return resultType.create(operandLength, false);
     }
@@ -211,50 +214,29 @@ public final class UnaryMapNode extends RBaseNode {
         result.copyNamesFrom(attributeSource);
     }
 
-    @SuppressWarnings("unused")
+    @ImportStatic(Utils.class)
     protected abstract static class MapUnaryVectorInternalNode extends RBaseNode {
 
-        private static final MapIndexedAction<byte[], RAbstractLogicalVector> LOGICAL = //
-                        (arithmetic, result, resultIndex, left, leftIndex) -> {
-                            result[resultIndex] = arithmetic.applyLogical(left.getDataAt(leftIndex));
-                        };
-
-        private static final MapIndexedAction<int[], RAbstractIntVector> INTEGER = //
-                        (arithmetic, result, resultIndex, left, leftIndex) -> {
-                            result[resultIndex] = arithmetic.applyInteger(left.getDataAt(leftIndex));
-                        };
-
-        private static final MapIndexedAction<double[], RAbstractDoubleVector> DOUBLE = //
-                        (arithmetic, result, resultIndex, left, leftIndex) -> {
-                            result[resultIndex] = arithmetic.applyDouble(left.getDataAt(leftIndex));
-                        };
-
-        private static final MapIndexedAction<double[], RAbstractComplexVector> COMPLEX = //
-                        (arithmetic, result, resultIndex, left, leftIndex) -> {
-                            RComplex value = arithmetic.applyComplex(left.getDataAt(leftIndex));
-                            result[resultIndex << 1] = value.getRealPart();
-                            result[(resultIndex << 1) + 1] = value.getImaginaryPart();
-                        };
-
-        private static final MapIndexedAction<double[], RAbstractComplexVector> DOUBLE_COMPLEX = //
-                        (arithmetic, result, resultIndex, left, leftIndex) -> {
-                            result[resultIndex] = arithmetic.applyDouble(left.getDataAt(leftIndex));
-                        };
-
-        private static final MapIndexedAction<String[], RAbstractStringVector> CHARACTER = //
-                        (arithmetic, result, resultIndex, left, leftIndex) -> {
-                            result[resultIndex] = arithmetic.applyCharacter(left.getDataAt(leftIndex));
-                        };
-
-        private final MapIndexedAction<Object, RAbstractVector> indexedAction;
+        private static final MapIndexedAction<Byte> LOGICAL = (arithmetic, value) -> arithmetic.applyLogical(value);
+        private static final MapIndexedAction<Integer> INTEGER = (arithmetic, value) -> arithmetic.applyInteger(value);
+        private static final MapIndexedAction<Double> DOUBLE = (arithmetic, value) -> arithmetic.applyDouble(value);
+        private static final MapIndexedAction<RComplex> COMPLEX = (arithmetic, value) -> arithmetic.applyComplex(value);
+        private static final MapIndexedAction<RComplex> DOUBLE_COMPLEX = (arithmetic, value) -> arithmetic.applyDouble(value);
+        private static final MapIndexedAction<String> CHARACTER = (arithmetic, value) -> arithmetic.applyCharacter(value);
+
+        private final MapIndexedAction<Object> indexedAction;
         private final RType argumentType;
         private final RType resultType;
 
+        @Child private GetDataStore getTargetDataStore = GetDataStore.create();
+        @Child private SetDataAt targetSetDataAt;
+
         @SuppressWarnings("unchecked")
         protected MapUnaryVectorInternalNode(RType resultType, RType argumentType) {
-            this.indexedAction = (MapIndexedAction<Object, RAbstractVector>) createIndexedAction(resultType, argumentType);
+            this.indexedAction = (MapIndexedAction<Object>) createIndexedAction(resultType, argumentType);
             this.argumentType = argumentType;
             this.resultType = resultType;
+            this.targetSetDataAt = Utils.createSetDataAtNode(resultType);
         }
 
         public RType getArgumentType() {
@@ -269,7 +251,7 @@ public final class UnaryMapNode extends RBaseNode {
             return MapUnaryVectorInternalNodeGen.create(resultType, argumentType);
         }
 
-        private static MapIndexedAction<? extends Object, ? extends RAbstractVector> createIndexedAction(RType resultType, RType argumentType) {
+        private static MapIndexedAction<?> createIndexedAction(RType resultType, RType argumentType) {
             switch (argumentType) {
                 case Logical:
                     return LOGICAL;
@@ -300,56 +282,38 @@ public final class UnaryMapNode extends RBaseNode {
             }
         }
 
-        private void apply(UnaryMapFunctionNode scalarAction, Object store, RAbstractVector operand, int operandLength) {
+        private void apply(UnaryMapFunctionNode scalarAction, RVector<?> target, RAbstractVector operand, int operandLength) {
             assert operand.getLength() == operandLength;
             assert operand.getRType() == argumentType;
-            assert isStoreCompatible(store, resultType, operandLength);
-
-            executeInternal(scalarAction, store, operand, operandLength);
-        }
-
-        private static boolean isStoreCompatible(Object store, RType resultType, int operandLength) {
-            switch (resultType) {
-                case Logical:
-                    assert store instanceof byte[] && ((byte[]) store).length == operandLength;
-                    return true;
-                case Integer:
-                    assert store instanceof int[] && ((int[]) store).length == operandLength;
-                    return true;
-                case Double:
-                    assert store instanceof double[] && ((double[]) store).length == operandLength;
-                    return true;
-                case Complex:
-                    assert store instanceof double[] && ((double[]) store).length >> 1 == operandLength;
-                    return true;
-                case Character:
-                    assert store instanceof String[] && ((String[]) store).length == operandLength;
-                    return true;
-                default:
-                    throw RInternalError.shouldNotReachHere();
-            }
+            executeInternal(scalarAction, target, operand, operandLength);
         }
 
         protected abstract void executeInternal(UnaryMapFunctionNode node, Object store, RAbstractVector operand, int operandLength);
 
         @Specialization(guards = {"operandLength == 1"})
-        protected void doScalar(UnaryMapFunctionNode node, Object store, RAbstractVector operand, int operandLength) {
-            indexedAction.perform(node, store, 0, operand, 0);
+        protected void doScalar(UnaryMapFunctionNode node, RVector<?> target, RAbstractVector operand, int operandLength,
+                        @Cached("createIterator()") VectorIterator.Generic iterator) {
+            Object it = iterator.init(operand);
+            Object targetStore = getTargetDataStore.execute(target);
+            Object value = iterator.next(operand, it);
+            targetSetDataAt.setDataAtAsObject(target, targetStore, 0, indexedAction.perform(node, value));
         }
 
         @Specialization(replaces = "doScalar")
-        protected void doScalarVector(UnaryMapFunctionNode node, Object store, RAbstractVector operand, int operandLength,
+        protected void doScalarVector(UnaryMapFunctionNode node, RVector<?> target, RAbstractVector operand, int operandLength,
+                        @Cached("createIterator()") VectorIterator.Generic iterator,
                         @Cached("createCountingProfile()") LoopConditionProfile profile) {
+            Object targetStore = getTargetDataStore.execute(target);
+            Object it = iterator.init(operand);
             profile.profileCounted(operandLength);
             for (int i = 0; profile.inject(i < operandLength); ++i) {
-                indexedAction.perform(node, store, i, operand, i);
+                Object value = indexedAction.perform(node, iterator.next(operand, it));
+                targetSetDataAt.setDataAtAsObject(target, targetStore, i, value);
             }
         }
 
-        private interface MapIndexedAction<A, V extends RAbstractVector> {
-
-            void perform(UnaryMapFunctionNode action, A store, int resultIndex, V operand, int operandIndex);
-
+        private interface MapIndexedAction<V> {
+            Object perform(UnaryMapFunctionNode action, V val);
         }
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ec6b0e3b7df1498e1acc23b969e9d1e86f2d34e
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.primitive;
+
+import com.oracle.truffle.r.runtime.RInternalError;
+import com.oracle.truffle.r.runtime.RType;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.SetDataAt;
+import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
+
+abstract class Utils {
+    private Utils() {
+    }
+
+    static SetDataAt createSetDataAtNode(RType type) {
+        switch (type) {
+            case Raw:
+                return SetDataAt.Raw.create();
+            case Logical:
+                return SetDataAt.Logical.create();
+            case Integer:
+                return SetDataAt.Int.create();
+            case Double:
+                return SetDataAt.Double.create();
+            case Complex:
+                return SetDataAt.Complex.create();
+            case Character:
+                return SetDataAt.String.create();
+            default:
+                throw RInternalError.shouldNotReachHere("BinaryMapNode unexpected result type " + type);
+        }
+    }
+
+    static final class VecStore<T extends RAbstractVector> {
+        public final T vector;
+        public final Object store;
+
+        VecStore(T vector, Object store) {
+            this.vector = vector;
+            this.store = store;
+        }
+    }
+
+    public static VectorIterator.Generic createIterator() {
+        return VectorIterator.Generic.create();
+    }
+
+    public static VectorIterator.Generic createIteratorWrapAround() {
+        return VectorIterator.Generic.createWrapAround();
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java
index b6ecdaa12c7c2a9938bc485faa4bbb4635a595e2..181686e7ab39cc3b6037564e06d9166a6ed7a101 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java
@@ -37,15 +37,13 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RComplex;
 import com.oracle.truffle.r.runtime.data.RComplexVector;
-import com.oracle.truffle.r.runtime.data.RDoubleSequence;
-import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RIntSequence;
-import com.oracle.truffle.r.runtime.data.RIntVector;
-import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RTypes;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorIterator;
 import com.oracle.truffle.r.runtime.interop.ForeignArray2R;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
@@ -202,16 +200,16 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected int doIntVector(RIntVector operand, boolean naRm, boolean finite,
-                              @Cached("new()") AccessVector.Int access) {
+    protected Object doIntVector(RAbstractIntVector operand, boolean naRm, boolean finite,
+                    @Cached("create()") VectorIterator.Int iterator) {
         RBaseNode.reportWork(this, operand.getLength());
         boolean profiledNaRm = naRmProfile.profile(naRm || finite);
         int result = semantics.getIntStart();
         na.enable(operand);
         int opCount = 0;
-        Object store = access.init(operand);
-        for (int i = 0; i < operand.getLength(); i++) {
-            int d = access.getDataAt(operand, store, i);
+        Object it = iterator.init(operand);
+        while (iterator.hasNext(operand, it)) {
+            int d = iterator.next(operand, it);
             if (na.check(d)) {
                 if (profiledNaRm) {
                     continue;
@@ -237,8 +235,8 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected double doDoubleVector(RDoubleVector operand, boolean naRm, boolean finite,
-                    @Cached("new()") AccessVector.Double access,
+    protected double doDoubleVector(RAbstractDoubleVector operand, boolean naRm, boolean finite,
+                    @Cached("create()") VectorIterator.Double iterator,
                     @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
                     @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) {
         RBaseNode.reportWork(this, operand.getLength());
@@ -247,9 +245,10 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
         double result = semantics.getDoubleStart();
         na.enable(operand);
         int opCount = 0;
-        Object store = access.init(operand);
-        for (int i = 0; i < operand.getLength(); i++) {
-            double d = access.getDataAt(operand, store, i);
+
+        Object it = iterator.init(operand);
+        while (iterator.hasNext(operand, it)) {
+            double d = iterator.next(operand, it);
             if (na.checkNAorNaN(d)) {
                 if (profiledNaRm) {
                     continue;   // ignore NA/NaN
@@ -274,16 +273,17 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected int doLogicalVector(RLogicalVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite,
-                                  @Cached("new()") AccessVector.Logical access) {
+    protected Object doLogicalVector(RAbstractLogicalVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite,
+                    @Cached("create()") VectorIterator.Logical iterator) {
         RBaseNode.reportWork(this, operand.getLength());
         boolean profiledNaRm = naRmProfile.profile(naRm);
         int result = semantics.getIntStart();
         na.enable(operand);
         int opCount = 0;
-        Object store = access.init(operand);
-        for (int i = 0; i < operand.getLength(); i++) {
-            byte d = access.getDataAt(operand, store, i);
+
+        Object it = iterator.init(operand);
+        while (iterator.hasNext(operand, it)) {
+            byte d = iterator.next(operand, it);
             if (na.check(d)) {
                 if (profiledNaRm) {
                     continue;
@@ -308,43 +308,6 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
         return result;
     }
 
-    @Specialization
-    protected Object doIntSequence(RIntSequence operand, @SuppressWarnings("unused") boolean naRm, @SuppressWarnings("unused") boolean finite) {
-        RBaseNode.reportWork(this, operand.getLength());
-        int result = semantics.getIntStart();
-        int current = operand.getStart();
-        for (int i = 0; i < operand.getLength(); i++) {
-            result = arithmetic.op(result, current);
-            if (RRuntime.isNA(result)) {
-                naResultWarning();
-                return RRuntime.INT_NA;
-            }
-            current += operand.getStride();
-        }
-        if (operand.getLength() == 0) {
-            emptyWarning();
-            if (semantics.isUseDoubleStartForEmptyVector()) {
-                return semantics.getDoubleStart();
-            }
-        }
-        return result;
-    }
-
-    @Specialization
-    protected double doDoubleSequence(RDoubleSequence operand, @SuppressWarnings("unused") boolean naRm, @SuppressWarnings("unused") boolean finite) {
-        RBaseNode.reportWork(this, operand.getLength());
-        double result = semantics.getDoubleStart();
-        double current = operand.getStart();
-        for (int i = 0; i < operand.getLength(); i++) {
-            result = arithmetic.op(result, current);
-            current += operand.getStride();
-        }
-        if (operand.getLength() == 0) {
-            emptyWarning();
-        }
-        return result;
-    }
-
     @Specialization(guards = "supportComplex")
     protected RComplex doComplexVector(RComplexVector operand, boolean naRm, boolean finite) {
         RBaseNode.reportWork(this, operand.getLength());
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java
index d87792ed941afb8bbe0c948cc31acc3e34cfca4a..4ba40b65984ec6251ce9df5be8e02effb52d9b29 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java
@@ -49,11 +49,11 @@ import com.oracle.truffle.r.runtime.data.nodes.VectorIterator.IteratorData;
 
 abstract class VectorIteratorNodeAdapter extends Node {
     public static boolean hasNoNativeMemoryData(RAbstractVector vector) {
-        return !(vector instanceof RVector) || !((RVector) vector).hasNativeMemoryData();
+        return !(vector instanceof RVector<?>) || !((RVector<?>) vector).hasNativeMemoryData();
     }
 
     public static boolean isRVector(RAbstractVector vector) {
-        return vector instanceof RVector;
+        return vector instanceof RVector<?>;
     }
 }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java
index 2a79a1339b1279cdf234b83520f240aa8b4381ac..1acc54576bcaa9a82c3d37a02ccec3d8b01fa094 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java
@@ -18,7 +18,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.nodes.AccessVector.DoubleAccessor;
+import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor;
 import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandomNumberProvider;
 
 public final class RMultinom {
@@ -32,7 +32,7 @@ public final class RMultinom {
      * prob[j]) , sum_j rN[j] == n, sum_j prob[j] == 1.
      */
     @TruffleBoundary
-    public static boolean rmultinom(int nIn, DoubleAccessor prob, int maxK, int[] rN, int rnStartIdx, RandomNumberProvider rand, Rbinom rbinom) {
+    public static boolean rmultinom(int nIn, ReadAccessor.Double prob, int maxK, int[] rN, int rnStartIdx, RandomNumberProvider rand, Rbinom rbinom) {
         /*
          * This calculation is sensitive to exact values, so we try to ensure that the calculations
          * are as accurate as possible so different platforms are more likely to give the same