diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
index 4a8ea1bfe1df35217683f504252afa0a464ed420..141b9841a229b852df644883d8de76e92ddcf47b 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java
@@ -766,7 +766,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
                 RList argsList = ((RPairList) args).toRList();
                 result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, true,
                                 ArgumentsSignature.fromNamesAttribute(argsList.getNames()),
-                                argsList.getDataNonShared());
+                                argsList.getDataTemp());
             }
         } else if (expr instanceof RSymbol) {
             RSyntaxNode lookup = RContext.getASTBuilder().lookup(RSyntaxNode.LAZY_DEPARSE, ((RSymbol) expr).getName(), false);
diff --git a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
index 5f4df74f1a5a34e275d289194cd536c06dd9ad88..06353f7b49c45aaf5fd2b08f1d60611c62df7c89 100644
--- a/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
+++ b/com.oracle.truffle.r.ffi.processor/src/com/oracle/truffle/r/ffi/processor/FFIProcessor.java
@@ -123,8 +123,12 @@ public final class FFIProcessor extends AbstractProcessor {
     private void generateTable(ExecutableElement[] methods) throws IOException {
         JavaFileObject fileObj = processingEnv.getFiler().createSourceFile("com.oracle.truffle.r.ffi.impl.upcalls.RFFIUpCallTable");
         Writer w = fileObj.openWriter();
-        w.append("// GENERATED; DO NOT EDIT\n");
+        w.append("// GENERATED by com.oracle.truffle.r.ffi.processor.FFIProcessor class; DO NOT EDIT\n");
         w.append("package com.oracle.truffle.r.ffi.impl.upcalls;\n");
+        w.append("/**\n" +
+                        " * The following enum contains an entry for each method in the interface annoated\n" +
+                        " * with @RFFIUpCallRoot including inherited methods.\n" +
+                        " */");
         w.append("public enum RFFIUpCallTable {\n");
         for (int i = 0; i < methods.length; i++) {
             ExecutableElement method = methods[i];
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 47a820c41aa22f757c6aeb7ab398585251bf28c8..e9b73da1514c22210656f0301bff85c889a10ec6 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
@@ -32,6 +32,8 @@ 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 {
@@ -49,6 +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("getMethod(method)") Method methodObj,
                     @Cached("create()") SetAttributeNode setAttrNode,
                     @Cached("create()") SetClassAttributeNode setClassAttrNode,
@@ -58,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(xm.getDataWithoutCopying(), nr, nc, ans, false, methodObj, p);
+        rdistance(new DoubleAccessor(x, xAccess), nr, nc, ans, false, methodObj, p);
         RDoubleVector result = RDataFactory.createDoubleVector(ans, naCheck.neverSeenNA());
         DynamicObject resultAttrs = result.initAttributes();
 
@@ -93,7 +96,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         return Method.values()[method - 1];
     }
 
-    private void rdistance(double[] x, int nr, int nc, double[] d, boolean diag, Method method, double p) {
+    private void rdistance(DoubleAccessor 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) {
@@ -106,7 +109,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         naCheck.enable(true);
         for (int j = 0; j <= nr; j++) {
             for (int i = j + dc; i < nr; i++) {
-                double r = method.dist(x, nr, nc, i, j, p);
+                double r = method.dist(xAccess, nr, nc, i, j, p);
                 naCheck.check(r);
                 d[ij++] = r;
             }
@@ -116,7 +119,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
     public enum Method {
         EUCLIDEAN {
             @Override
-            public double dist(double[] x, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -127,8 +130,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(x[i1], x[i2])) {
-                        dev = (x[i1] - x[i2]);
+                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
+                        dev = (xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             dist += dev * dev;
                             count++;
@@ -149,7 +152,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MAXIMUM {
             @Override
-            public double dist(double[] x, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -160,8 +163,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = -Double.MAX_VALUE;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(x[i1], x[i2])) {
-                        dev = Math.abs(x[i1] - x[i2]);
+                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
+                        dev = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             if (dev > dist) {
                                 dist = dev;
@@ -181,7 +184,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MANHATTAN {
             @Override
-            public double dist(double[] x, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -192,8 +195,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(x[i1], x[i2])) {
-                        dev = Math.abs(x[i1] - x[i2]);
+                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
+                        dev = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             dist += dev;
                             count++;
@@ -214,7 +217,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         CANBERRA {
             @Override
-            public double dist(double[] x, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -227,9 +230,9 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(x[i1], x[i2])) {
-                        sum = Math.abs(x[i1] + x[i2]);
-                        diff = Math.abs(x[i1] - x[i2]);
+                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
+                        sum = Math.abs(xAccess.getDataAt(i1) + xAccess.getDataAt(i2));
+                        diff = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
                         if (sum > DBL_MIN || diff > DBL_MIN) {
                             dev = diff / sum;
                             if (!RRuntime.isNAorNaN(dev) ||
@@ -255,7 +258,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         BINARY {
             @Override
-            public double dist(double[] x, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 int total;
@@ -268,13 +271,13 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 dist = 0;
 
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(x[i1], x[i2])) {
-                        if (!bothFinite(x[i1], x[i2])) {
+                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
+                        if (!bothFinite(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
                             RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, "treating non-finite values as NA");
                         } else {
-                            if (x[i1] != 0. || x[i2] != 0.) {
+                            if (xAccess.getDataAt(i1) != 0. || xAccess.getDataAt(i2) != 0.) {
                                 count++;
-                                if (!(x[i1] != 0. && x[i2] != 0.)) {
+                                if (!(xAccess.getDataAt(i1) != 0. && xAccess.getDataAt(i2) != 0.)) {
                                     dist++;
                                 }
                             }
@@ -297,7 +300,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
         },
         MINKOWSKI {
             @Override
-            public double dist(double[] x, int nr, int nc, final int i1in, final int i2in, double p) {
+            public double dist(DoubleAccessor xAccess, int nr, int nc, final int i1in, final int i2in, double p) {
                 int i1 = i1in;
                 int i2 = i2in;
                 double dev;
@@ -308,8 +311,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
                 count = 0;
                 dist = 0;
                 for (j = 0; j < nc; j++) {
-                    if (bothNonNAN(x[i1], x[i2])) {
-                        dev = (x[i1] - x[i2]);
+                    if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) {
+                        dev = (xAccess.getDataAt(i1) - xAccess.getDataAt(i2));
                         if (!RRuntime.isNAorNaN(dev)) {
                             dist += Math.pow(Math.abs(dev), p);
                             count++;
@@ -328,6 +331,6 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 {
             }
         };
 
-        public abstract double dist(double[] x, int nr, int nc, int i1, int i2, double p);
+        public abstract double dist(DoubleAccessor 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/Cutree.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java
index d4f616e70c5549f6e549c139b0dc12099410b1b5..4bb86b4814f961b6c24be2ff3d46766a7771ad2b 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
@@ -10,8 +10,8 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyIntegerVector;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -20,6 +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;
 
 // translated from library/stats/src/hclust_utils.c
 
@@ -32,10 +33,10 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
     }
 
     @Specialization
-    protected RIntVector cutree(RAbstractIntVector mergeIn, RAbstractIntVector whichIn,
+    protected RIntVector cutree(RAbstractIntVector merge, RAbstractIntVector which,
+                    @Cached("new()") AccessVector.Int mergeAccess,
+                    @Cached("new()") AccessVector.Int whichAccess,
                     @Cached("create()") GetDimAttributeNode getDimNode) {
-        RIntVector merge = mergeIn.materialize();
-        RIntVector which = whichIn.materialize();
         int whichLen = which.getLength();
 
         int j;
@@ -58,8 +59,8 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
         int[] z = new int[n];
 
         int[] iAns = new int[n * whichLen];
-        int[] iMerge = merge.getDataWithoutCopying();
-        int[] iWhich = which.getDataWithoutCopying();
+        Object mergeStore = mergeAccess.init(merge);
+        Object whichStore = whichAccess.init(which);
 
         // for (k = 1; k <= n; k++) {
         for (k = 0; k < n; k++) {
@@ -69,8 +70,8 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
 
         for (k = 1; k <= n - 1; k++) {
             /* k-th merge, from n-k+1 to n-k atoms: (m1,m2) = merge[ k , ] */
-            m1 = iMerge[k - 1];
-            m2 = iMerge[n - 1 + k - 1];
+            m1 = mergeAccess.getDataAt(merge, mergeStore, k - 1);
+            m2 = mergeAccess.getDataAt(merge, mergeStore, n - 1 + k - 1);
 
             if (m1 < 0 && m2 < 0) { /* merging atoms [-m1] and [-m2] */
                 mNr[adj(-m1)] = mNr[adj(-m2)] = k;
@@ -104,7 +105,7 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
              */
             foundJ = false;
             for (j = 0; j < whichLen; j++) {
-                if (iWhich[j] == n - k) {
+                if (whichAccess.getDataAt(which, whichStore, j) == n - k) {
                     if (!foundJ) { /* first match (and usually only one) */
                         foundJ = true;
                         // for (l = 1; l <= n; l++)
@@ -134,7 +135,7 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 {
 
         /* Dealing with trivial case which[] = n : */
         for (j = 0; j < whichLen; j++) {
-            if (iWhich[j] == n) {
+            if (whichAccess.getDataAt(which, whichStore, j) == n) {
                 for (l = 1, m1 = j * n; l <= n; l++, m1++) {
                     iAns[m1] = l;
                 }
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 9f35e9ded8df6ad2204d774c96389f66549ffc9d..b1b5b7c187e27f3f64ebfebeee367ecff6cf03a3 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
@@ -10,8 +10,8 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -20,6 +20,7 @@ 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;
 
 public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
 
@@ -30,29 +31,31 @@ public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 {
 
     @Specialization
     protected RDoubleVector doubleCentre(RAbstractDoubleVector aVecAbs,
+                    @Cached("new()") AccessVector.Double aAccess,
                     @Cached("create()") GetDimAttributeNode getDimNode) {
         RDoubleVector aVec = aVecAbs.materialize();
         int n = getDimNode.nrows(aVec);
-        double[] a = aVec.getDataWithoutCopying(); // does not copy
-
+        Object aStore = aAccess.init(aVec);
         for (int i = 0; i < n; i++) {
             double sum = 0;
             for (int j = 0; j < n; j++) {
-                sum += a[i + j * n];
+                sum += aAccess.getDataAt(aVec, aStore, i + j * n);
             }
             sum /= n;
             for (int j = 0; j < n; j++) {
-                a[i + j * n] -= sum;
+                double val = aAccess.getDataAt(aVec, aStore, i + j * n);
+                aAccess.setDataAt(aVec, aStore, i + j * n, val - sum);
             }
         }
         for (int j = 0; j < n; j++) {
             double sum = 0;
             for (int i = 0; i < n; i++) {
-                sum += a[i + j * n];
+                sum += aAccess.getDataAt(aVec, aStore, i + j * n);
             }
             sum /= n;
             for (int i = 0; i < n; i++) {
-                a[i + j * n] -= sum;
+                double val = aAccess.getDataAt(aVec, aStore, i + j * n);
+                aAccess.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 0379b9d46dfdf186173170d2d399bd36c5ce55f2..8167a7610c109ba64237738c0739f3ef33bb9599 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
@@ -14,8 +14,8 @@ package com.oracle.truffle.r.library.stats;
 
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyDoubleVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notIntNA;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
 import static com.oracle.truffle.r.runtime.RError.Message.NA_IN_PROB_VECTOR;
 import static com.oracle.truffle.r.runtime.RError.Message.NEGATIVE_PROBABILITY;
 import static com.oracle.truffle.r.runtime.RError.Message.NO_POSITIVE_PROBABILITIES;
@@ -32,9 +32,12 @@ import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
+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.nmath.RandomFunctions.RandomNumberProvider;
 import com.oracle.truffle.r.runtime.nmath.distr.RMultinom;
 import com.oracle.truffle.r.runtime.nmath.distr.Rbinom;
@@ -65,19 +68,20 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
 
     @Specialization
     protected RIntVector doMultinom(int n, int size, RAbstractDoubleVector probsVec,
+                    @Cached("new()") AccessVector.Double probsAccess,
                     @Cached("create()") ReuseNonSharedNode reuseNonSharedNode,
                     @Cached("createClassProfile()") ValueProfile randGeneratorClassProfile,
                     @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile,
                     @Cached("create()") UpdateShareableChildValueNode updateSharedAttributeNode,
                     @Cached("createNames()") GetFixedAttributeNode getNamesNode,
                     @Cached("createDimNames()") SetFixedAttributeNode setDimNamesNode) {
-        RAbstractDoubleVector nonSharedProbs = (RAbstractDoubleVector) reuseNonSharedNode.execute(probsVec);
-        double[] probs = nonSharedProbs.materialize().getDataWithoutCopying();
-        fixupProb(probs);
+        RDoubleVector nonSharedProbs = ((RAbstractDoubleVector) reuseNonSharedNode.execute(probsVec)).materialize();
+        DoubleAccessor probs = new DoubleAccessor(nonSharedProbs, probsAccess);
+        fixupProb(nonSharedProbs, probs.store, probsAccess);
 
         RRNG.getRNGState();
         RandomNumberProvider rand = new RandomNumberProvider(randGeneratorClassProfile.profile(RRNG.currentGenerator()), RRNG.currentNormKind());
-        int k = probs.length;
+        int k = probs.vector.getLength();
         int[] result = new int[k * n];
         boolean isComplete = true;
         for (int i = 0, ik = 0; i < n; i++, ik += k) {
@@ -96,10 +100,12 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
         return resultVec;
     }
 
-    private void fixupProb(double[] p) {
+    private void fixupProb(RDoubleVector p, Object pStore, AccessVector.Double pAccess) {
         double sum = 0.0;
         int npos = 0;
-        for (double prob : p) {
+        int pLength = p.getLength();
+        for (int i = 0; i < pLength; i++) {
+            double prob = pAccess.getDataAt(p, pStore, i);
             if (!Double.isFinite(prob)) {
                 throw error(NA_IN_PROB_VECTOR);
             }
@@ -114,8 +120,9 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 {
         if (npos == 0) {
             throw error(NO_POSITIVE_PROBABILITIES);
         }
-        for (int i = 0; i < p.length; i++) {
-            p[i] /= sum;
+        for (int i = 0; i < pLength; i++) {
+            double prob = pAccess.getDataAt(p, pStore, i);
+            pAccess.setDataAt(p, pStore, i, prob / sum);
         }
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java
index 2af07cc9e5d58828686678f3503daa476edb5c3a..f5046039d3ef3d828236f0261e127caa80c3bc1b 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SplineFunctions.java
@@ -88,7 +88,7 @@ public class SplineFunctions {
             double[] c = new double[n];
             double[] d = new double[n];
 
-            SplineFunctions.splineCoef(method, n, x.getDataWithoutCopying(), y.getDataWithoutCopying(), b, c, d);
+            SplineFunctions.splineCoef(method, n, x.getReadonlyData(), y.getReadonlyData(), b, c, d);
 
             final boolean complete = x.isComplete() && y.isComplete();
             RDoubleVector bv = RDataFactory.createDoubleVector(b, complete);
@@ -421,8 +421,8 @@ public class SplineFunctions {
         RDoubleVector c = (RDoubleVector) z.getDataAt(z.getElementIndexByName("c"));
         RDoubleVector d = (RDoubleVector) z.getDataAt(z.getElementIndexByName("d"));
 
-        splineEval(method, nu, xout.getDataWithoutCopying(), yout, nx, x.getDataWithoutCopying(), y.getDataWithoutCopying(), b.getDataWithoutCopying(), c.getDataWithoutCopying(),
-                        d.getDataWithoutCopying());
+        splineEval(method, nu, xout.getReadonlyData(), yout, nx, x.getReadonlyData(), y.getReadonlyData(), b.getReadonlyData(), c.getReadonlyData(),
+                        d.getReadonlyData());
         return RDataFactory.createDoubleVector(yout, xout.isComplete() && x.isComplete() && y.isComplete());
     }
 
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 ec765e5a52901a9f96ca97ee9c14af841a886072..ee14351e7b93cc44b31ab3ceb978d7c1fae92ecc 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
@@ -12,11 +12,11 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.emptyDoubleVector;
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -46,6 +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.nmath.MathFunctions.Function2_1;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function2_2;
 import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function3_1;
@@ -363,8 +365,8 @@ public final class StatsFunctionsNodes {
 
         static {
             Casts casts = new Casts(Approx.class);
-            casts.arg(0).mustBe(instanceOf(RDoubleVector.class));
-            casts.arg(1).mustBe(instanceOf(RDoubleVector.class));
+            casts.arg(0).mustBe(doubleValue());
+            casts.arg(1).mustBe(doubleValue());
             casts.arg(2).mustBe(missingValue().not()).mapIf(nullValue(), emptyDoubleVector()).asDoubleVector();
             casts.arg(3).asIntegerVector().findFirst();
             casts.arg(4).asDoubleVector().findFirst();
@@ -373,7 +375,9 @@ public final class StatsFunctionsNodes {
         }
 
         @Specialization
-        protected RDoubleVector approx(RDoubleVector x, RDoubleVector y, RAbstractDoubleVector v, int method, double yl, double yr, double f) {
+        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) {
             int nx = x.getLength();
             int nout = v.getLength();
             double[] yout = new double[nout];
@@ -385,9 +389,12 @@ public final class StatsFunctionsNodes {
             apprMeth.ylow = yl;
             apprMeth.yhigh = yr;
             naCheck.enable(true);
+
+            DoubleAccessor xAccessor = new DoubleAccessor(x, xAccess);
+            DoubleAccessor yAccessor = new DoubleAccessor(y, yAccess);
             for (int i = 0; i < nout; i++) {
                 double xouti = v.getDataAt(i);
-                yout[i] = RRuntime.isNAorNaN(xouti) ? xouti : approx1(xouti, x.getDataWithoutCopying(), y.getDataWithoutCopying(), nx, apprMeth);
+                yout[i] = RRuntime.isNAorNaN(xouti) ? xouti : approx1(xouti, xAccessor, yAccessor, nx, apprMeth);
                 naCheck.check(yout[i]);
             }
             return RDataFactory.createDoubleVector(yout, naCheck.neverSeenNA());
@@ -401,8 +408,8 @@ public final class StatsFunctionsNodes {
             int kind;
         }
 
-        private static double approx1(double v, double[] x, double[] y, int n,
-                        ApprMeth apprMeth) {
+        private static double approx1(double v, DoubleAccessor x, DoubleAccessor y, int n,
+                                      ApprMeth apprMeth) {
             /* Approximate y(v), given (x,y)[i], i = 0,..,n-1 */
             int i;
             int j;
@@ -416,17 +423,17 @@ public final class StatsFunctionsNodes {
             j = n - 1;
 
             /* handle out-of-domain points */
-            if (v < x[i]) {
+            if (v < x.getDataAt(i)) {
                 return apprMeth.ylow;
             }
-            if (v > x[j]) {
+            if (v > x.getDataAt(j)) {
                 return apprMeth.yhigh;
             }
 
             /* find the correct interval by bisection */
-            while (i < j - 1) { /* x[i] <= v <= x[j] */
+            while (i < j - 1) { /* x.getDataAt(i) <= v <= x.getDataAt(j) */
                 ij = (i + j) / 2; /* i+1 <= ij <= j-1 */
-                if (v < x[ij]) {
+                if (v < x.getDataAt(ij)) {
                     j = ij;
                 } else {
                     i = ij;
@@ -437,18 +444,18 @@ public final class StatsFunctionsNodes {
 
             /* interpolation */
 
-            if (v == x[j]) {
-                return y[j];
+            if (v == x.getDataAt(j)) {
+                return y.getDataAt(j);
             }
-            if (v == x[i]) {
-                return y[i];
+            if (v == x.getDataAt(i)) {
+                return y.getDataAt(i);
             }
-            /* impossible: if(x[j] == x[i]) return y[i]; */
+            /* impossible: if(x.getDataAt(j) == x.getDataAt(i)) return y.getDataAt(i); */
 
             if (apprMeth.kind == 1) { /* linear */
-                return y[i] + (y[j] - y[i]) * ((v - x[i]) / (x[j] - x[i]));
+                return y.getDataAt(i) + (y.getDataAt(j) - y.getDataAt(i)) * ((v - x.getDataAt(i)) / (x.getDataAt(j) - x.getDataAt(i)));
             } else { /* 2 : constant */
-                return (apprMeth.f1 != 0.0 ? y[i] * apprMeth.f1 : 0.0) + (apprMeth.f2 != 0.0 ? y[j] * apprMeth.f2 : 0.0);
+                return (apprMeth.f1 != 0.0 ? y.getDataAt(i) * apprMeth.f1 : 0.0) + (apprMeth.f2 != 0.0 ? y.getDataAt(j) * apprMeth.f2 : 0.0);
             }
         }/* approx1() */
 
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 3b4ca6fb6ce7420ac66d24bb5791682dd2dfa6c9..0b0041f6e72690ce43716b6a75d4daf6e94ccea0 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,6 +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;
 
 /**
  * Implements the basic logic for {@code crossprod} and {@code tcrossprod}. Either the first matrix
@@ -101,6 +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()") GetDimAttributeNode getDimsNode,
                     @Cached("create()") GetDimAttributeNode getResultDimsNode) {
         int[] xDims = getDimsNode.getDimensions(x);
@@ -110,7 +112,8 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 {
         int yCols = transposeX ? xDims[1] : xDims[0];
         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);
+                        getResultDimsNode,
+                        vectorToArrayNode);
         return copyDimNames(x, x, result);
     }
 
@@ -169,13 +172,13 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 {
         return result;
     }
 
-    private static RDoubleVector mirror(RDoubleVector result, GetDimAttributeNode getResultDimsNode) {
+    private static RDoubleVector mirror(RDoubleVector result, GetDimAttributeNode getResultDimsNode, VectorToArray vectorToArrayNode) {
         // 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 = result.getDataWithoutCopying();
+        double[] data = vectorToArrayNode.getReadonly(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/DoCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
index 271e4ac0bd5980f0966e60189d3f043000dab43e..b864672ccb2bf20855dffd1ce73434cc8524af59 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java
@@ -28,8 +28,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
 import static com.oracle.truffle.r.runtime.RVisibility.CUSTOM;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX;
 
-import java.util.Arrays;
-
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
@@ -145,11 +143,9 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta
                         @Cached("createBinaryProfile()") ConditionProfile quoteProfile,
                         @Cached("create()") BranchProfile containsRSymbolProfile,
                         @Cached("createClassProfile()") ValueProfile frameAccessProfile) {
-            Object[] argValuesData = argsAsList.getDataWithoutCopying();
-            Object[] argValues = argValuesData;
+            Object[] argValues = argsAsList.getDataCopy();
             MaterializedFrame envFrame = env.getFrame(frameAccessProfile).materialize();
             if (quoteProfile.profile(!quote)) {
-                argValues = Arrays.copyOf(argValuesData, argValuesData.length);
                 for (int i = 0; i < argValues.length; i++) {
                     Object arg = argValues[i];
                     if (arg instanceof RSymbol) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
index 0be5eb231324116a9ac7c2f4639f52f6a8a19496..a5b17287ed083383a96af787d33adb6a8cf64bbb 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java
@@ -847,7 +847,7 @@ public class FileFunctions {
                 if (elem instanceof String) {
                     inputs[i] = new String[]{(String) elem};
                 } else if (elem instanceof RStringVector) {
-                    inputs[i] = ((RStringVector) elem).getDataWithoutCopying();
+                    inputs[i] = ((RStringVector) elem).getReadonlyData();
                 } else {
                     throw error(RError.Message.NON_STRING_ARG_TO_INTERNAL_PASTE);
                 }
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 48044327ef71962c683e810d0c5fffc8d4a0834e..8902a830b06761acf78c1589a33f1bd759f088f9 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
@@ -32,6 +32,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 import java.lang.ref.SoftReference;
 import java.util.function.Function;
 
+import com.oracle.truffle.api.CompilerDirectives;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.Cached;
@@ -43,6 +44,7 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode;
 import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
+import com.oracle.truffle.r.nodes.attributes.UnaryCopyAttributesNode;
 import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.unary.CastDoubleNode;
@@ -60,6 +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.ffi.LapackRFFI;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
@@ -317,20 +320,19 @@ public class LaFunctions {
         }
 
         @Specialization
-        protected RDoubleVector doQrCoefReal(RList qIn, RAbstractDoubleVector bIn,
+        protected RDoubleVector doQrCoefReal(RList qIn, RAbstractDoubleVector b,
+                        @Cached("create()") VectorToArray qrToArrayNode,
+                        @Cached("create()") VectorToArray tauToArrayNode,
                         @Cached("create()") GetDimAttributeNode getBDimsNode,
                         @Cached("create()") GetDimAttributeNode getQDimsNode,
                         @Cached("create()") LapackRFFI.DormqrNode dormqrNode,
                         @Cached("create()") LapackRFFI.DtrtrsNode dtrtrsNode) {
-            // If bIn was coerced this extra copy is unnecessary
-            RDoubleVector b = (RDoubleVector) bIn.copy();
-
             RDoubleVector qr = (RDoubleVector) qIn.getDataAt(0);
 
             RDoubleVector tau = (RDoubleVector) qIn.getDataAt(2);
             int k = tau.getLength();
 
-            int[] bDims = getBDimsNode.getDimensions(bIn);
+            int[] bDims = getBDimsNode.getDimensions(b);
             int[] qrDims = getQDimsNode.getDimensions(qr);
             int n = qrDims[0];
             if (bDims[0] != n) {
@@ -339,10 +341,10 @@ public class LaFunctions {
             int nrhs = bDims[1];
             double[] work = new double[1];
             // qr and tau do not really need copying
-            double[] qrData = qr.getDataWithoutCopying();
-            double[] tauData = tau.getDataWithoutCopying();
-            // we work directly in the internal data of b
-            double[] bData = b.getDataWithoutCopying();
+            double[] qrData = qrToArrayNode.getReadonly(qr);
+            double[] tauData = tauToArrayNode.getReadonly(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
             int info = dormqrNode.execute(SIDE, TRANS, n, nrhs, k, qrData, n, tauData, bData, n, work, -1);
             if (info < 0) {
@@ -359,7 +361,7 @@ public class LaFunctions {
                 throw error(Message.LAPACK_ERROR, info, "dtrtrs");
             }
             // TODO check complete
-            return b;
+            return RDataFactory.createDoubleVector(bData, RDataFactory.INCOMPLETE_VECTOR);
         }
     }
 
@@ -385,6 +387,7 @@ public class LaFunctions {
         @Specialization
 
         protected RList doDetGeReal(RAbstractDoubleVector aIn, boolean useLog,
+                        @Cached("create()") VectorToArray vectorToArrayNode,
                         @Cached("create()") GetDimAttributeNode getDimsNode,
                         @Cached("create()") LapackRFFI.DgetrfNode dgetrfNode) {
             RDoubleVector a = (RDoubleVector) aIn.copy();
@@ -392,7 +395,7 @@ public class LaFunctions {
             int n = aDims[0];
             int[] ipiv = new int[n];
             double modulus = 0;
-            double[] aData = a.getDataWithoutCopying();
+            double[] aData = vectorToArrayNode.getReadonly(a);
             int info = dgetrfNode.execute(n, n, aData, n, ipiv);
             int sign = 1;
             if (info < 0) {
@@ -465,51 +468,63 @@ public class LaFunctions {
 
         @Specialization
         protected RDoubleVector doDetGeReal(RAbstractDoubleVector aIn, boolean piv, double tol,
+                        @Cached("create()") UnaryCopyAttributesNode copyAttributesNode,
                         @Cached("create()") GetDimAttributeNode getDimsNode,
                         @Cached("create()") SetDimNamesAttributeNode setDimNamesNode,
                         @Cached("create()") GetDimNamesAttributeNode getDimNamesNode,
                         @Cached("create()") LapackRFFI.DpotrfNode dpotrfNode,
                         @Cached("create()") LapackRFFI.DpstrfNode dpstrfNode) {
-            RDoubleVector a = (RDoubleVector) aIn.copy();
+            double[] aData = aIn.materialize().getDataCopy();
             int[] aDims = getDimsNode.getDimensions(aIn);
             int n = aDims[0];
             int m = aDims[1];
-            double[] aData = a.getDataWithoutCopying();
             /* zero the lower triangle */
             for (int j = 0; j < n; j++) {
                 for (int i = j + 1; i < n; i++) {
                     aData[i + n * j] = 0;
                 }
             }
+
             int info;
             if (noPivot.profile(!piv)) {
                 info = dpotrfNode.execute('U', m, aData, m);
                 if (info != 0) {
-                    // TODO informative error message (aka GnuR)
-                    throw error(Message.LAPACK_ERROR, info, "dpotrf");
+                    CompilerDirectives.transferToInterpreter();
+                    if (info > 0) {
+                        throw error(Message.LAPACK_CHOL_NOT_POSITIVE_DEFINITE, info);
+                    } else {
+                        throw error(Message.LAPACK_ERROR, info, "dpotrf");
+                    }
                 }
-            } else {
-                int[] ipiv = new int[m];
-                double[] work = new double[2 * m];
-                int[] rank = new int[1];
-                info = dpstrfNode.execute('U', n, aData, n, ipiv, rank, tol, work);
-                if (info != 0) {
-                    // TODO informative error message (aka GnuR)
+                return (RDoubleVector) copyAttributesNode.execute(RDataFactory.createDoubleVector(aData, RDataFactory.INCOMPLETE_VECTOR), aIn);
+            }
+
+            int[] ipiv = new int[m];
+            double[] work = new double[2 * m];
+            int[] rank = new int[1];
+            info = dpstrfNode.execute('U', n, aData, n, ipiv, rank, tol, work);
+            if (info != 0) {
+                CompilerDirectives.transferToInterpreter();
+                if (info > 0) {
+                    throw error(Message.LAPACK_CHOL_RANK_DEF_OR_INDEF, info);
+                } else {
                     throw error(Message.LAPACK_ERROR, info, "dpotrf");
                 }
-                setPivotAttrNode.execute(a, RRuntime.asLogical(piv));
-                setRankAttrNode.execute(a, rank[0]);
-                RList dn = getDimNamesNode.getDimNames(a);
-                if (dn != null && dn.getDataAt(0) != null) {
-                    Object[] dn2 = new Object[m];
-                    // need to pivot the colnames
-                    for (int i = 0; i < m; i++) {
-                        dn2[i] = dn.getDataAt(ipiv[i] - 1);
-                    }
-                    setDimNamesNode.setDimNames(a, RDataFactory.createList(dn2));
+            }
+
+            RDoubleVector result = (RDoubleVector) copyAttributesNode.execute(RDataFactory.createDoubleVector(aData, RDataFactory.INCOMPLETE_VECTOR), aIn);
+            setPivotAttrNode.execute(result, RRuntime.asLogical(piv));
+            setRankAttrNode.execute(result, rank[0]);
+            RList dn = getDimNamesNode.getDimNames(aIn);
+            if (dn != null && dn.getDataAt(0) != null) {
+                Object[] dn2 = new Object[m];
+                // need to pivot the colnames
+                for (int i = 0; i < m; i++) {
+                    dn2[i] = dn.getDataAt(ipiv[i] - 1);
                 }
+                setDimNamesNode.setDimNames(result, RDataFactory.createList(dn2));
             }
-            return a;
+            return result;
         }
     }
 
@@ -684,9 +699,10 @@ public class LaFunctions {
             double[] avals;
             if (aDouble.isShared()) {
                 avals = aCache.get(aDouble.getLength());
-                System.arraycopy(aDouble.getDataWithoutCopying(), 0, avals, 0, n * p);
+                // TODO: fixme more efficient copying
+                System.arraycopy(aDouble.getDataCopy(), 0, avals, 0, n * p);
             } else {
-                avals = aDouble.getDataWithoutCopying();
+                avals = aDouble.getDataCopy();
             }
             int info = dgesvNode.execute(n, p, avals, n, ipiv, bData, n);
             if (info < 0) {
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 1321af4d0cebde99a813941ce1a431b947371831..bddcb8ae9ddcea89c572c7bd7d4363be1daf4b4c 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,6 +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.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
@@ -150,6 +151,9 @@ 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();
+
     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);
     }
@@ -176,8 +180,8 @@ public abstract class MatMult extends RBuiltinNode.Arg2 {
         if (aCols != bRows) {
             throw error(RError.Message.NON_CONFORMABLE_ARGS);
         }
-        double[] dataA = a.materialize().getDataWithoutCopying();
-        double[] dataB = b.materialize().getDataWithoutCopying();
+        double[] dataA = aToArrayNode.getReadonly(a.materialize());
+        double[] dataB = bToArrayNode.getReadonly(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 c2ededbc786e8ec0835efb45edd40b2f4176718c..c7f2e016619af2ea22b6d472d57d526a009824c9 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
@@ -20,6 +20,7 @@ import static com.oracle.truffle.r.runtime.RError.Message.INVALID_LOGICAL;
 import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
 import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
 
+import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
@@ -30,6 +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;
 
 /**
  * Note: invoked from merge.data.frame.
@@ -79,7 +81,9 @@ public abstract class Merge extends RBuiltinNode.Arg4 {
     }
 
     @Specialization
-    RList merge(RAbstractIntVector xIndsAbstract, RAbstractIntVector yIndsAbstract, boolean allX, boolean allY) {
+    RList merge(RAbstractIntVector xIndsAbstract, RAbstractIntVector yIndsAbstract, boolean allX, boolean allY,
+                    @Cached("create()") VectorToArray xIndsToArray,
+                    @Cached("create()") VectorToArray yIndsToArray) {
         RIntVector xInds = xIndsAbstract.materialize();
         RIntVector yInds = yIndsAbstract.materialize();
 
@@ -94,8 +98,8 @@ public abstract class Merge extends RBuiltinNode.Arg4 {
         for (int i = 0; i < ny; i++) {
             iy[i] = i + 1;
         }
-        int[] xIndsData = xInds.getDataWithoutCopying();
-        int[] yIndsData = yInds.getDataWithoutCopying();
+        int[] xIndsData = xIndsToArray.getReadonly(xInds);
+        int[] yIndsData = yIndsToArray.getReadonly(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/Paste.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
index 55a76080cb08370639afb5555aaf5e0a806f9f3f..4db45a113dcfb5ff6de7ba0969a2e32853477643 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java
@@ -152,7 +152,7 @@ public abstract class Paste extends RBuiltinNode.Arg3 {
         int emptyCnt = 0;
         for (int i = 0; i < length; i++) {
             Object element = values.getDataAt(i);
-            String[] array = castCharacterVector(frame, element).materialize().getDataWithoutCopying();
+            String[] array = castCharacterVector(frame, element).materialize().getReadonlyData();
             maxLength = Math.max(maxLength, array.length);
             if (array.length == 0) {
                 converted[i] = ONE_EMPTY_STRING;
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 0069d9e8851782c95f4c4ac00845a5c264c49550..57d232e5c9617d276e19f65246073deb5ff2b49d 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,6 +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;
 
 /**
  * The {@code split} internal. Internal version of 'split' is invoked from 'split.default' function
@@ -63,6 +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();
 
     private static final int INITIAL_SIZE = 5;
     private static final int SCALE_FACTOR = 2;
@@ -73,7 +75,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractListVector x, RAbstractIntVector f) {
-        int[] factor = f.materialize().getDataWithoutCopying();
+        Object fStore = factorAccess.init(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -85,8 +87,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         // perform split
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factor.length)) {
-            int resultIndex = factor[fi] - 1; // a factor is a 1-based int vector
+        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
             Object[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -96,7 +99,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         Object[] results = new Object[nLevels];
-        RStringVector[] resultNames = getNames(x, factor, nLevels, collectResultSize);
+        RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize);
         for (int i = 0; i < nLevels; i++) {
             results[i] = RDataFactory.createList(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]),
                             (resultNames != null) ? resultNames[i] : null);
@@ -106,7 +109,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractIntVector x, RAbstractIntVector f) {
-        int[] factor = f.materialize().getDataWithoutCopying();
+        Object fStore = factorAccess.init(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -118,8 +121,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         // perform split
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factor.length)) {
-            int resultIndex = factor[fi] - 1; // a factor is a 1-based int vector
+        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[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -129,7 +133,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         Object[] results = new Object[nLevels];
-        RStringVector[] resultNames = getNames(x, factor, nLevels, collectResultSize);
+        RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize);
         for (int i = 0; i < nLevels; i++) {
             results[i] = RDataFactory.createIntVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(),
                             (resultNames != null) ? resultNames[i] : null);
@@ -139,7 +143,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractDoubleVector x, RAbstractIntVector f) {
-        int[] factor = f.materialize().getDataWithoutCopying();
+        Object fStore = factorAccess.init(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -151,8 +155,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         // perform split
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factor.length)) {
-            int resultIndex = factor[fi] - 1; // a factor is a 1-based int vector
+        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
             double[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -162,7 +167,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         Object[] results = new Object[nLevels];
-        RStringVector[] resultNames = getNames(x, factor, nLevels, collectResultSize);
+        RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize);
         for (int i = 0; i < nLevels; i++) {
             results[i] = RDataFactory.createDoubleVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), RDataFactory.COMPLETE_VECTOR,
                             (resultNames != null) ? resultNames[i] : null);
@@ -172,7 +177,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractStringVector x, RAbstractIntVector f) {
-        int[] factor = f.materialize().getDataWithoutCopying();
+        Object fStore = factorAccess.init(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -184,8 +189,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         // perform split
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factor.length)) {
-            int resultIndex = factor[fi] - 1; // a factor is a 1-based int vector
+        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
             String[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -195,7 +201,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         Object[] results = new Object[nLevels];
-        RStringVector[] resultNames = getNames(x, factor, nLevels, collectResultSize);
+        RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize);
         for (int i = 0; i < nLevels; i++) {
             results[i] = RDataFactory.createStringVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), RDataFactory.COMPLETE_VECTOR,
                             (resultNames != null) ? resultNames[i] : null);
@@ -205,7 +211,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RAbstractLogicalVector x, RAbstractIntVector f) {
-        int[] factor = f.materialize().getDataWithoutCopying();
+        Object fStore = factorAccess.init(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -217,8 +223,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         // perform split
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factor.length)) {
-            int resultIndex = factor[fi] - 1; // a factor is a 1-based int vector
+        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
             byte[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -228,7 +235,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         Object[] results = new Object[nLevels];
-        RStringVector[] resultNames = getNames(x, factor, nLevels, collectResultSize);
+        RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize);
         for (int i = 0; i < nLevels; i++) {
             results[i] = RDataFactory.createLogicalVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(),
                             (resultNames != null) ? resultNames[i] : null);
@@ -238,7 +245,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
 
     @Specialization
     protected RList split(RRawVector x, RAbstractIntVector f) {
-        int[] factor = f.materialize().getDataWithoutCopying();
+        Object fStore = factorAccess.init(f);
         RStringVector names = getLevelNode.execute(f);
         final int nLevels = getNLevels(names);
 
@@ -250,8 +257,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         // perform split
-        for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factor.length)) {
-            int resultIndex = factor[fi] - 1; // a factor is a 1-based int vector
+        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
             byte[] collect = collectResults[resultIndex];
             if (collect.length == collectResultSize[resultIndex]) {
                 collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR);
@@ -261,7 +269,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         }
 
         Object[] results = new Object[nLevels];
-        RStringVector[] resultNames = getNames(x, factor, nLevels, collectResultSize);
+        RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize);
         for (int i = 0; i < nLevels; i++) {
             results[i] = RDataFactory.createRawVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]),
                             (resultNames != null) ? resultNames[i] : null);
@@ -269,7 +277,7 @@ public abstract class Split extends RBuiltinNode.Arg2 {
         return RDataFactory.createList(results, names);
     }
 
-    private RStringVector[] getNames(RAbstractVector x, int[] factor, int nLevels, int[] collectResultSize) {
+    private RStringVector[] getNames(RAbstractVector x, RAbstractIntVector factor, Object fStore, int nLevels, int[] collectResultSize) {
         RStringVector xNames = getNamesNode.getNames(x);
         if (namesProfile.profile(xNames != null)) {
             String[][] namesArr = new String[nLevels][];
@@ -277,8 +285,9 @@ public abstract class Split extends RBuiltinNode.Arg2 {
             for (int i = 0; i < nLevels; i++) {
                 namesArr[i] = new String[collectResultSize[i]];
             }
-            for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factor.length)) {
-                int resultIndex = factor[fi] - 1; // a factor is a 1-based int vector
+            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
                 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 00fbadeb93c2ed6e3bb8c7923f10a38ebf9865c7..aa0cd2a7d0bd8017a4615264e7c6ba9686a6b60c 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,6 +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.ffi.MiscRFFI;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
@@ -74,6 +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("naRm") boolean cachedNaRm,
                     @Cached("create()") VectorLengthProfile lengthProfile,
                     @Cached("createCountingProfile()") LoopConditionProfile loopProfile,
@@ -84,7 +86,7 @@ public abstract class Sum extends RBuiltinNode.Arg2 {
         int length = lengthProfile.profile(vector.getLength());
 
         if (needsExactSumProfile.profile(length >= 3)) {
-            return exactSumNode.execute(vector.getDataWithoutCopying(), !vector.isComplete(), cachedNaRm);
+            return exactSumNode.execute(vectorToArrayNode.getReadonly(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/infix/UpdateSubscript.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
index 36cf01ffbe3ead88ac0e13686cea150534705af0..dee733d610767ce17f9da037ee79639076c60102 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/UpdateSubscript.java
@@ -83,7 +83,7 @@ abstract class UpdateSubscriptSpecial extends SubscriptSpecialCommon {
 
     @Specialization(guards = {"simpleVector(list)", "!list.isShared()", "isValidIndex(list, index)", "isSingleElement(value)"})
     protected static Object set(RList list, int index, Object value) {
-        list.setDataAt(list.getInternalStore(), index - 1, value);
+        list.setDataAt(index - 1, value);
         return list;
     }
 
@@ -130,7 +130,7 @@ abstract class UpdateSubscriptSpecial2 extends SubscriptSpecial2Common {
 
     @Specialization(guards = {"simpleVector(list)", "!list.isShared()", "isValidIndex(list, index1, index2)", "isSingleElement(value)"})
     protected Object set(RList list, int index1, int index2, Object value) {
-        list.setDataAt(list.getInternalStore(), matrixIndex(list, index1, index2), value);
+        list.setDataAt(matrixIndex(list, index1, index2), value);
         return list;
     }
 
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
index 62a9cba7c6bf912bc59c8a61e5c4c5c4e0abb916..4a3d4606b1ef7486d3927e80e7847a1b1d3013f0 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/S3FunctionLookupNode.java
@@ -11,7 +11,6 @@
 package com.oracle.truffle.r.nodes.function;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 import com.oracle.truffle.api.CompilerDirectives;
@@ -160,7 +159,11 @@ public abstract class S3FunctionLookupNode extends RBaseNode {
                 if (i == 0) {
                     dispatchType = type.copyResized(type.getLength(), false);
                 } else {
-                    RStringVector clazz = RDataFactory.createStringVector(Arrays.copyOfRange(type.getDataWithoutCopying(), i, type.getLength()), true);
+                    String[] clazzData = new String[type.getLength() - i];
+                    for (int j = i; j < type.getLength(); j++) {
+                        clazzData[j - i] = type.getDataAt(j);
+                    }
+                    RStringVector clazz = RDataFactory.createStringVector(clazzData, true);
                     clazz.setAttr(RRuntime.PREVIOUS_ATTR_KEY, type.copyResized(type.getLength(), false));
                     dispatchType = clazz;
                 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java
index 28fe8a13b4c821b874880fe25407165efb736743..686c14ef60b48334fc09d3341535f15a69b03d97 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java
@@ -28,10 +28,10 @@ import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.BranchProfile;
 import com.oracle.truffle.api.profiles.ConditionProfile;
 import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode;
+import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNode;
 import com.oracle.truffle.r.nodes.unary.CastStringNodeGen;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -71,6 +71,7 @@ public final class RFactorNodes {
     public static final class GetLevels extends Node {
         @Child private CastStringNode castString;
         @Child private GetFixedAttributeNode attrAccess = GetFixedAttributeNode.create(RRuntime.LEVELS_ATTR_KEY);
+        @Child UpdateShareableChildValueNode updateAttrValue = UpdateShareableChildValueNode.create();
 
         private final BranchProfile notVectorBranch = BranchProfile.create();
         private final ConditionProfile nonScalarLevels = ConditionProfile.createBinaryProfile();
@@ -85,7 +86,7 @@ public final class RFactorNodes {
          * cast is done. May return null, if the 'levels' attribute is not present.
          */
         public RStringVector execute(RAbstractIntVector factor) {
-            Object attr = attrAccess.execute(factor.getAttributes());
+            Object attr = updateAttrValue.updateState(factor, attrAccess.execute(factor.getAttributes()));
 
             // Convert scalars to vector if necessary
             RAbstractVector vec;
@@ -110,7 +111,8 @@ public final class RFactorNodes {
                     castString = insert(CastStringNodeGen.create(false, false, false));
                 }
                 RStringVector slevels = ((RAbstractStringVector) castString.executeString(vec)).materialize();
-                return RDataFactory.createStringVector(slevels.getDataWithoutCopying(), RDataFactory.COMPLETE_VECTOR);
+                assert slevels.isTemporary() : "cast should create a new tmp vector since !(vec instanceof RStringVector)";
+                return slevels;
             }
         }
     }
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 369ea71c7184823354b34bb077956e5a4d42d99a..b6ecdaa12c7c2a9938bc485faa4bbb4635a595e2 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
@@ -45,6 +45,7 @@ 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.interop.ForeignArray2R;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.BinaryArithmetic;
@@ -201,15 +202,16 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected Object doIntVector(RIntVector operand, boolean naRm, boolean finite) {
+    protected int doIntVector(RIntVector operand, boolean naRm, boolean finite,
+                              @Cached("new()") AccessVector.Int access) {
         RBaseNode.reportWork(this, operand.getLength());
         boolean profiledNaRm = naRmProfile.profile(naRm || finite);
         int result = semantics.getIntStart();
         na.enable(operand);
         int opCount = 0;
-        int[] data = operand.getDataWithoutCopying();
+        Object store = access.init(operand);
         for (int i = 0; i < operand.getLength(); i++) {
-            int d = data[i];
+            int d = access.getDataAt(operand, store, i);
             if (na.check(d)) {
                 if (profiledNaRm) {
                     continue;
@@ -236,6 +238,7 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
 
     @Specialization
     protected double doDoubleVector(RDoubleVector operand, boolean naRm, boolean finite,
+                    @Cached("new()") AccessVector.Double access,
                     @Cached("createBinaryProfile()") ConditionProfile finiteProfile,
                     @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) {
         RBaseNode.reportWork(this, operand.getLength());
@@ -244,9 +247,9 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
         double result = semantics.getDoubleStart();
         na.enable(operand);
         int opCount = 0;
-        double[] data = operand.getDataWithoutCopying();
+        Object store = access.init(operand);
         for (int i = 0; i < operand.getLength(); i++) {
-            double d = data[i];
+            double d = access.getDataAt(operand, store, i);
             if (na.checkNAorNaN(d)) {
                 if (profiledNaRm) {
                     continue;   // ignore NA/NaN
@@ -271,15 +274,16 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode {
     }
 
     @Specialization
-    protected Object doLogicalVector(RLogicalVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite) {
+    protected int doLogicalVector(RLogicalVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite,
+                                  @Cached("new()") AccessVector.Logical access) {
         RBaseNode.reportWork(this, operand.getLength());
         boolean profiledNaRm = naRmProfile.profile(naRm);
         int result = semantics.getIntStart();
         na.enable(operand);
         int opCount = 0;
-        byte[] data = operand.getDataWithoutCopying();
+        Object store = access.init(operand);
         for (int i = 0; i < operand.getLength(); i++) {
-            byte d = data[i];
+            byte d = access.getDataAt(operand, store, i);
             if (na.check(d)) {
                 if (profiledNaRm) {
                     continue;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
index 6dedde1535352ed78b38f7aa66e496d2e6ccf3ad..d8a18bfca7d19bc019bea4df248d9ef5acf477ef 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java
@@ -76,7 +76,8 @@ public final class ArgumentsSignature implements Iterable<String> {
      * converted to {@code null} value.
      */
     public static ArgumentsSignature fromNamesAttribute(RStringVector names) {
-        return names == null ? null : get(names.getDataWithoutCopying(), true);
+        // Note: get makes a defensive copy of names anyway
+        return names == null ? null : get(names.getReadonlyData(), true);
     }
 
     @TruffleBoundary
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index c0a021efa81949f83664786c0f8bb8d7fac9ff8f..c1436c21875cad6f14b507610bc5423a9c86e7e0 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -573,6 +573,8 @@ public final class RError extends RuntimeException implements TruffleException {
         LAPACK_INVALID_VALUE("argument %d of Lapack routine %s had invalid value"),
         LAPACK_ZERO_INVERSE("element (%d, %d) is zero, so the inverse cannot be computed"),
         LAPACK_EXACTLY_SINGULAR("Lapack routine %s: system is exactly singular: U[%d,%d] = 0"),
+        LAPACK_CHOL_NOT_POSITIVE_DEFINITE("the leading minor of order %d is not positive definite"),
+        LAPACK_CHOL_RANK_DEF_OR_INDEF("the matrix is either rank-deficient or indefinite"),
         SYSTEM_COMP_SINGULAR("system is computationally singular: reciprocal condition number = %g"),
         RHS_SHOULD_HAVE_ROWS("right-hand side should have %d not %d rows"),
         SAME_NUMBER_ROWS("'%s' and '%s' must have the same number of rows"),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index 00ed14aecea4faa1e75f344e508768d4e918f48c..93c1cab891f025f44824415e9707b8aca331a55f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -318,7 +318,7 @@ public class RSerialize {
 
     @TruffleBoundary
     public static Object unserialize(RAbstractRawVector data) {
-        byte[] buffer = data.materialize().getDataWithoutCopying();
+        byte[] buffer = data.materialize().getReadonlyData();
         try {
             return new Input(new ByteArrayInputStream(buffer)).unserialize();
         } catch (IOException e) {
@@ -1520,10 +1520,10 @@ public class RSerialize {
                              * matter, so we use the "frame" form, which is a pairlist. tag is
                              * binding name, car is binding value
                              */
-                            String[] bindings = env.ls(true, null, false).getDataWithoutCopying();
-                            for (String binding : bindings) {
-                                Object value = getValueIgnoreActiveBinding(env.getFrame(), binding);
-                                writePairListEntry(binding, value);
+                            RStringVector bindings = env.ls(true, null, false);
+                            for (int i = 0; i < bindings.getLength(); i++) {
+                                Object value = getValueIgnoreActiveBinding(env.getFrame(), bindings.getDataAt(i));
+                                writePairListEntry(bindings.getDataAt(i), value);
                             }
                             terminatePairList();
                             writeItem(RNull.instance); // hashtab
@@ -1631,7 +1631,7 @@ public class RSerialize {
 
                             case RAWSXP: {
                                 RRawVector raw = (RRawVector) obj;
-                                byte[] data = raw.getDataWithoutCopying();
+                                byte[] data = raw.getReadonlyData();
                                 stream.writeInt(data.length);
                                 stream.writeRaw(data);
                                 break;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java
index 341f5e16bfe88ba760be8ebedbc9fc0c6a7cd6d2..6b3fdc386347450f0f2eaafbb1ec09508d14ec23 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java
@@ -235,9 +235,9 @@ public class TextConnections {
         }
 
         void appendData(String[] appendedData) {
-            String[] existingData = textVec != null ? textVec.getDataWithoutCopying() : new String[0];
             String[] updateData = appendedData;
-            if (existingData.length > 0) {
+            if (textVec != null && textVec.getLength() > 0) {
+                String[] existingData = textVec.getReadonlyData();
                 updateData = new String[existingData.length + appendedData.length];
                 System.arraycopy(existingData, 0, updateData, 0, existingData.length);
                 System.arraycopy(appendedData, 0, updateData, existingData.length, appendedData.length);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
index 8822d7b40175edbb0e8a889a5cde0896b4d3ec09..f8c9740e0670919634015cd2f65032f6d833872d 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java
@@ -74,14 +74,38 @@ class UnsafeAdapter {
     }
 }
 
+/**
+ * Provides API to work with objects returned by {@link RObject#getNativeMirror()}. The native
+ * mirror represents what on the native side is SEXP, but not directly the raw data of the vector.
+ * Use {@link #asPointer(Object)} to assign a native mirror object to the given vector. The raw data
+ * in native memory for a vector that already has a native mirror object assigned can be allocated
+ * using e.g. {@link #allocateNativeContents(RIntVector, int[], int)} .
+ * 
+ * There is a registry of weak references to all native mirrors ever assigned to some vector object.
+ * We use the finalizer to free the native memory (if allocated).
+ */
 public final class NativeDataAccess {
     private NativeDataAccess() {
         // no instances
     }
 
+    public static boolean isNativeMirror(Object o) {
+        return o instanceof NativeMirror;
+    }
+
     private static final class NativeMirror {
+        /**
+         * ID of the mirror, this will be used as the value for SEXP. When native up-calls to Java,
+         * we get this value and find the corresponding object for it.
+         */
         private final long id;
+        /**
+         * Address of the start of the native memory array. Zero if not allocated yet.
+         */
         private long dataAddress;
+        /**
+         * Length of the native data array. E.g. for CHARSXP this is not just the length of the Java String.
+         */
         private long length;
 
         NativeMirror() {
@@ -141,6 +165,9 @@ public final class NativeDataAccess {
         });
     }
 
+    /**
+     * Assigns a native mirror object to the given RObject object.
+     */
     public static long asPointer(Object arg) {
         if (arg instanceof RObject) {
             RObject obj = (RObject) arg;
@@ -161,6 +188,9 @@ public final class NativeDataAccess {
         return obj;
     }
 
+    /**
+     * For given native mirror ID returns the Java side object (vector).
+     */
     public static Object lookup(long address) {
         WeakReference<RObject> reference = nativeMirrors.get(address);
         if (reference == null) {
@@ -175,6 +205,72 @@ public final class NativeDataAccess {
         return result;
     }
 
+    // methods operating on the native mirror object directly:
+
+    public static int getIntNativeMirrorData(Object nativeMirror, int index) {
+        long address = ((NativeMirror) nativeMirror).dataAddress;
+        assert address != 0;
+        assert index < ((NativeMirror) nativeMirror).length;
+        return UnsafeAdapter.UNSAFE.getInt(address + index * Unsafe.ARRAY_INT_INDEX_SCALE);
+    }
+
+    public static double getDoubleNativeMirrorData(Object nativeMirror, int index) {
+        long address = ((NativeMirror) nativeMirror).dataAddress;
+        assert address != 0;
+        assert index < ((NativeMirror) nativeMirror).length;
+        return UnsafeAdapter.UNSAFE.getDouble(address + index * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
+    }
+
+    public static byte getLogicalNativeMirrorData(Object nativeMirror, int index) {
+        long address = ((NativeMirror) nativeMirror).dataAddress;
+        assert address != 0;
+        assert index < ((NativeMirror) nativeMirror).length;
+        return RRuntime.int2logical(UnsafeAdapter.UNSAFE.getInt(address + index * Unsafe.ARRAY_INT_INDEX_SCALE));
+    }
+
+    public static byte getRawNativeMirrorData(Object nativeMirror, int index) {
+        long address = ((NativeMirror) nativeMirror).dataAddress;
+        assert address != 0;
+        assert index < ((NativeMirror) nativeMirror).length;
+        return UnsafeAdapter.UNSAFE.getByte(address + index * Unsafe.ARRAY_BYTE_INDEX_SCALE);
+    }
+
+    public static void setNativeMirrorData(Object nativeMirror, int index, double value) {
+        long address = ((NativeMirror) nativeMirror).dataAddress;
+        assert address != 0;
+        assert index < ((NativeMirror) nativeMirror).length;
+        UnsafeAdapter.UNSAFE.putDouble(address + index * Unsafe.ARRAY_DOUBLE_INDEX_SCALE, value);
+    }
+
+    public static double[] copyDoubleNativeData(Object mirrorObj) {
+        NativeMirror mirror = (NativeMirror) mirrorObj;
+        long address = mirror.dataAddress;
+        assert address != 0;
+        double[] data = new double[(int) mirror.length];
+        UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, data.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
+        return data;
+    }
+
+    public static int[] copyIntNativeData(Object mirrorObj) {
+        NativeMirror mirror = (NativeMirror) mirrorObj;
+        long address = mirror.dataAddress;
+        assert address != 0;
+        int[] data = new int[(int) mirror.length];
+        UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_INT_BASE_OFFSET, data.length * Unsafe.ARRAY_INT_INDEX_SCALE);
+        return data;
+    }
+
+    public static byte[] copyByteNativeData(Object mirrorObj) {
+        NativeMirror mirror = (NativeMirror) mirrorObj;
+        long address = mirror.dataAddress;
+        assert address != 0;
+        byte[] data = new byte[(int) mirror.length];
+        UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_BYTE_BASE_OFFSET, data.length * Unsafe.ARRAY_BYTE_INDEX_SCALE);
+        return data;
+    }
+
+    // methods operating on vectors that may have a native mirror assigned:
+
     private static final Assumption noIntNative = Truffle.getRuntime().createAssumption();
     private static final Assumption noLogicalNative = Truffle.getRuntime().createAssumption();
     private static final Assumption noDoubleNative = Truffle.getRuntime().createAssumption();
@@ -186,9 +282,7 @@ public final class NativeDataAccess {
         if (noIntNative.isValid() || data != null) {
             return data[index];
         } else {
-            long address = ((NativeMirror) vector.getNativeMirror()).dataAddress;
-            assert address != 0;
-            return UnsafeAdapter.UNSAFE.getInt(address + index * Unsafe.ARRAY_INT_INDEX_SCALE);
+            return getIntNativeMirrorData(vector.getNativeMirror(), index);
         }
     }
 
@@ -242,9 +336,7 @@ public final class NativeDataAccess {
         if (noRawNative.isValid() || data != null) {
             return data[index];
         } else {
-            long address = ((NativeMirror) vector.getNativeMirror()).dataAddress;
-            assert address != 0;
-            return UnsafeAdapter.UNSAFE.getByte(address + index * Unsafe.ARRAY_BYTE_INDEX_SCALE);
+            return getRawNativeMirrorData(vector.getNativeMirror(), index);
         }
     }
 
@@ -270,9 +362,7 @@ public final class NativeDataAccess {
         if (noDoubleNative.isValid() || data != null) {
             return data[index];
         } else {
-            long address = ((NativeMirror) vector.getNativeMirror()).dataAddress;
-            assert address != 0;
-            return UnsafeAdapter.UNSAFE.getDouble(address + index * Unsafe.ARRAY_INT_INDEX_SCALE);
+            return getDoubleNativeMirrorData(vector.getNativeMirror(), index);
         }
     }
 
@@ -288,9 +378,7 @@ public final class NativeDataAccess {
         if (noDoubleNative.isValid() || data != null) {
             data[index] = value;
         } else {
-            long address = ((NativeMirror) vector.getNativeMirror()).dataAddress;
-            assert address != 0;
-            UnsafeAdapter.UNSAFE.putDouble(address + index * Unsafe.ARRAY_INT_INDEX_SCALE, value);
+            setNativeMirrorData(vector.getNativeMirror(), index, value);
         }
     }
 
@@ -300,8 +388,8 @@ public final class NativeDataAccess {
         } else {
             long address = ((NativeMirror) vector.getNativeMirror()).dataAddress;
             assert address != 0;
-            return RComplex.valueOf(UnsafeAdapter.UNSAFE.getDouble(address + index * 2 * Unsafe.ARRAY_INT_INDEX_SCALE),
-                            UnsafeAdapter.UNSAFE.getDouble(address + (index * 2 + 1) * Unsafe.ARRAY_INT_INDEX_SCALE));
+            return RComplex.valueOf(UnsafeAdapter.UNSAFE.getDouble(address + index * 2 * Unsafe.ARRAY_DOUBLE_INDEX_SCALE),
+                            UnsafeAdapter.UNSAFE.getDouble(address + (index * 2 + 1) * Unsafe.ARRAY_DOUBLE_INDEX_SCALE));
         }
     }
 
@@ -320,8 +408,8 @@ public final class NativeDataAccess {
         } else {
             long address = ((NativeMirror) vector.getNativeMirror()).dataAddress;
             assert address != 0;
-            UnsafeAdapter.UNSAFE.putDouble(address + index * 2 * Unsafe.ARRAY_INT_INDEX_SCALE, re);
-            UnsafeAdapter.UNSAFE.putDouble(address + (index * 2 + 1) * Unsafe.ARRAY_INT_INDEX_SCALE, im);
+            UnsafeAdapter.UNSAFE.putDouble(address + index * 2 * Unsafe.ARRAY_DOUBLE_INDEX_SCALE, re);
+            UnsafeAdapter.UNSAFE.putDouble(address + (index * 2 + 1) * Unsafe.ARRAY_DOUBLE_INDEX_SCALE, im);
         }
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
index 207dc2d50e3bc6777cdbb15f068a4d92ad1455f1..d84e75629f1a8fbc967095b3a3efc5c1a45f1a93 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java
@@ -55,6 +55,11 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
         return new RComplexVector(Arrays.copyOf(data, data.length), this.isComplete());
     }
 
+    @Override
+    public double[] getInternalManagedData() {
+        return data;
+    }
+
     @Override
     public double[] getInternalStore() {
         return data;
@@ -119,12 +124,8 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract
         return Arrays.copyOf(data, data.length);
     }
 
-    /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
-     */
     @Override
-    public double[] getDataWithoutCopying() {
+    public double[] getReadonlyData() {
         assert data != null;
         return data;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java
index d1a8ced337293f4efa4ddd8a33aacd444a9308f2..b14fb519c88aad3e608ee5b598334bd6090f1998 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java
@@ -72,6 +72,11 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
         return new RDoubleVector(Arrays.copyOf(data, data.length), this.isComplete());
     }
 
+    @Override
+    public double[] getInternalManagedData() {
+        return data;
+    }
+
     @Override
     public double[] getInternalStore() {
         return data;
@@ -135,12 +140,8 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD
         return Arrays.copyOf(data, data.length);
     }
 
-    /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
-     */
     @Override
-    public double[] getDataWithoutCopying() {
+    public double[] getReadonlyData() {
         assert data != null;
         return data;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java
index 42be6bdb5eeffc6592a4ce953a8da75b3f0c7aa5..bb21a383242e321095bbf9ff51512b3a8c19ef0e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java
@@ -136,12 +136,13 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect
         return Arrays.copyOf(data, data.length);
     }
 
-    /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
-     */
     @Override
-    public int[] getDataWithoutCopying() {
+    public int[] getInternalManagedData() {
+        return data;
+    }
+
+    @Override
+    public int[] getReadonlyData() {
         assert data != null;
         return data;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
index 305e605d2621b422c7365abfb63dfe30646abe25..73cb3411ce64c3a449726641d3dc8242367315de 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java
@@ -109,15 +109,23 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi
         return true;
     }
 
+    @Override
+    public Object[] getInternalManagedData() {
+        return data;
+    }
+
     /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
+     * Unlike atomic vectors, {@code RList} cannot have a native memory mirror, therefore this is a
+     * fast operation.
      */
-    @Override
-    public final Object[] getDataWithoutCopying() {
+    public final Object[] getReadonlyData() {
         return data;
     }
 
+    public final Object[] getDataWithoutCopying() {
+        return getReadonlyData();
+    }
+
     @Override
     public final Object[] getDataCopy() {
         Object[] copy = new Object[data.length];
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
index 14902799427cd5c0566c906eb610bbb48da21b92..0eee40bd3acf6cad1eb87e06bf94fb9131bcee43 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java
@@ -68,6 +68,11 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
         }
     }
 
+    @Override
+    public byte[] getInternalManagedData() {
+        return data;
+    }
+
     @Override
     public byte[] getInternalStore() {
         assert data != null;
@@ -187,12 +192,8 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo
         return Arrays.copyOf(data, data.length);
     }
 
-    /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
-     */
     @Override
-    public byte[] getDataWithoutCopying() {
+    public byte[] getReadonlyData() {
         assert data != null;
         return data;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
index fb6529e506d085bd21d1147de19e3a4a299fe00f..5771c618e3554fdbe2ce03fc7564a3a2245d9deb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java
@@ -66,6 +66,11 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
         }
     }
 
+    @Override
+    public byte[] getInternalManagedData() {
+        return data;
+    }
+
     @Override
     public byte[] getInternalStore() {
         return data;
@@ -120,12 +125,8 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec
         return Arrays.copyOf(data, data.length);
     }
 
-    /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
-     */
     @Override
-    public byte[] getDataWithoutCopying() {
+    public byte[] getReadonlyData() {
         assert data != null;
         return data;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java
index 7fb2ffdad2bb3f978fda84fe63838ba6e1095ef1..b0e42cf3ac099c4b0717cf5404b37f71613974ab 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java
@@ -61,6 +61,11 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
         }
     }
 
+    @Override
+    public String[] getInternalManagedData() {
+        return data;
+    }
+
     @Override
     public String[] getInternalStore() {
         return data;
@@ -108,12 +113,8 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS
         return result;
     }
 
-    /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
-     */
     @Override
-    public String[] getDataWithoutCopying() {
+    public String[] getReadonlyData() {
         return data;
     }
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
index 846193104cbe95021aa0b18859b180ce2e6c6235..16e53cf26ee6b3014a75e21ccc4c48369289a3bf 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java
@@ -39,6 +39,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.data.nodes.VectorToArray;
 import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 import com.oracle.truffle.r.runtime.ops.na.NACheck;
 
@@ -84,35 +85,52 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement
         }
     }
 
+    /**
+     * Returns the internal data Java array for read only purposes only or {@code null} if the
+     * vector has been materialized to native mirror and it does not hold managed data anymore. This
+     * method is for only very specific purposes especially of {@link VectorToArray}.
+     *
+     * @return vector data
+     */
+    public abstract ArrayT getInternalManagedData();
+
     /**
      * Intended for external calls where a mutable copy is needed.
      */
     public abstract ArrayT getDataCopy();
 
     /**
-     * Intended for external calls where a copy is not needed. WARNING: think carefully before using
-     * this method rather than {@link #getDataCopy()}.
+     * Returns data for read-only purposes. The result may or may not be copy of the internal data.
+     * This is a slow path operation for vector types that may have a native mirror, use
+     * {@link VectorToArray} node for fast path in such cases.
+     *
+     * @see VectorToArray
+     * @see RObject#getNativeMirror()
+     * @return vector data
      */
-    public abstract ArrayT getDataWithoutCopying();
+    public abstract ArrayT getReadonlyData();
 
     /**
-     * Return vector data (copying if necessary) that's guaranteed not to be shared with any other
-     * vector instance (but maybe non-temporary in terms of vector's sharing mode).
+     * Return vector data (copying if necessary) that's guaranteed to be either temporary in terms
+     * of vector sharing mode, or owned by only one location (non-shared). It is not safe to re-use
+     * the array returned to create a new vector.
      *
      * @return vector data
      */
     public final ArrayT getDataNonShared() {
-        return isShared() ? getDataCopy() : getDataWithoutCopying();
+        return !isShared() ? getReadonlyData() : getDataCopy();
     }
 
     /**
      * Return vector data (copying if necessary) that's guaranteed to be "fresh" (temporary in terms
-     * of vector sharing mode).
+     * of vector sharing mode). As long as the vector is not retuned or put into a list/environment
+     * (i.e. if it is temporary, it will stay temporary), it is safe to reuse the array retuned by
+     * this method to create a new vector.
      *
      * @return vector data
      */
     public final ArrayT getDataTemp() {
-        return isTemporary() ? getDataWithoutCopying() : getDataCopy();
+        return isTemporary() ? getReadonlyData() : getDataCopy();
     }
 
     @Override
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
index 5afbae372907df8ac0f98640c8a71f1ce1a17f66..928229bfae518308c85b04370c86df5d66a28c40 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java
@@ -58,6 +58,15 @@ public interface RAbstractContainer extends RAttributable, RTypedValue {
         return getDataAtAsObject(index);
     }
 
+    /**
+     * Returns an object that could be passed to {@link #getDataAtAsObject(Object, int)} or type
+     * specialized versions in concrete vector types. The {@code store} object should contain data
+     * necessary for the vector to perform {@link #getDataAtAsObject(Object, int)} and similar
+     * methods without any field loads. If {@code store} is saved into a local variable, then the
+     * {@code getDataAsObject} overloads with {@code store} parameter do not have to load the
+     * vector's fields, but instead read the necessary data from a local variable, which could be
+     * beneficial when in loop.
+     */
     default Object getInternalStore() {
         return null;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
index a932ec25774ba052f178f8b757ed468ac516fba4..c5cb2fe28d7ed2164b885310c67de92827874ca7 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java
@@ -154,15 +154,6 @@ public abstract class REnvironment extends RAttributeStorage {
         @Override
         public void beforeDispose(RContext context) {
             beforeDestroyContext(context, this);
-            for (FrameSlot slot : globalFrame.getFrameDescriptor().getSlots()) {
-                if (globalFrame.isObject(slot)) {
-                    globalFrame.setObject(slot, null);
-                }
-            }
-            baseEnv = null;
-            namespaceRegistry = null;
-            searchPath = null;
-            parentGlobalFrame = null;
         }
 
         public static ContextStateImpl newContextState(RContext context) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java
index 24685419efb0e382b59e3599281dfcabb4d94d6e..b8cb17148db018cb5284aaaef45bcd444fd95efd 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java
@@ -191,7 +191,9 @@ public final class RScope extends AbstractScope {
 
         private String[] ls() {
             RStringVector ls = frameAccess.ls(true, null, false);
-            return ls.getDataWithoutCopying();
+            // we make a defensive copy, another option would be to make the vector shared and reuse
+            // the underlying array
+            return ls.getDataCopy();
         }
 
         public static boolean isInstance(TruffleObject obj) {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
index bcb0a801559bbe7faf54e60d9d85b835a8fa5881..37e2afc0d46ce0a0e101c3cdb02cd334b9916bca 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java
@@ -46,6 +46,7 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RLogicalVector;
 import com.oracle.truffle.r.runtime.data.RRawVector;
 import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.RVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
@@ -117,7 +118,7 @@ abstract class TemporaryWrapper implements TruffleObject {
     protected long address;
     protected RAbstractAtomicVector vector;
 
-    public TemporaryWrapper(RAbstractAtomicVector vector) {
+    TemporaryWrapper(RAbstractAtomicVector vector) {
         this.vector = vector;
     }
 
@@ -145,11 +146,16 @@ abstract class TemporaryWrapper implements TruffleObject {
     }
 
     protected abstract RAbstractAtomicVector copyBack();
+
+    protected static <ArrayT> ArrayT reuseData(RVector<ArrayT> vec) {
+        // Note: maybe we can reuse non-shared vectors too?
+        return vec.isTemporary() ? vec.getInternalManagedData() : null;
+    }
 }
 
 final class StringWrapper extends TemporaryWrapper {
 
-    public StringWrapper(RAbstractStringVector vector) {
+    StringWrapper(RAbstractStringVector vector) {
         super(vector);
     }
 
@@ -181,7 +187,10 @@ final class StringWrapper extends TemporaryWrapper {
     @TruffleBoundary
     protected RStringVector copyBack() {
         RStringVector result = ((RAbstractStringVector) vector).materialize();
-        String[] data = result.isTemporary() ? result.getDataWithoutCopying() : result.getDataCopy();
+        String[] data = reuseData(result);
+        if (data == null) {
+            data = new String[result.getLength()];
+        }
         for (int i = 0; i < data.length; i++) {
             long ptr = UnsafeAdapter.UNSAFE.getLong(address + i * 8);
             int length = 0;
@@ -199,7 +208,7 @@ final class StringWrapper extends TemporaryWrapper {
 
 final class IntWrapper extends TemporaryWrapper {
 
-    public IntWrapper(RAbstractIntVector vector) {
+    IntWrapper(RAbstractIntVector vector) {
         super(vector);
     }
 
@@ -219,7 +228,10 @@ final class IntWrapper extends TemporaryWrapper {
     @TruffleBoundary
     protected RIntVector copyBack() {
         RIntVector result = ((RAbstractIntVector) vector).materialize();
-        int[] data = result.isTemporary() ? result.getDataWithoutCopying() : result.getDataCopy();
+        int[] data = reuseData(result);
+        if (data == null) {
+            data = new int[vector.getLength()];
+        }
         UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_INT_BASE_OFFSET, vector.getLength() * Unsafe.ARRAY_INT_INDEX_SCALE);
         UnsafeAdapter.UNSAFE.freeMemory(address);
         return RDataFactory.createIntVector(data, false);
@@ -228,7 +240,7 @@ final class IntWrapper extends TemporaryWrapper {
 
 final class LogicalWrapper extends TemporaryWrapper {
 
-    public LogicalWrapper(RAbstractLogicalVector vector) {
+    LogicalWrapper(RAbstractLogicalVector vector) {
         super(vector);
     }
 
@@ -248,7 +260,10 @@ final class LogicalWrapper extends TemporaryWrapper {
     @TruffleBoundary
     protected RLogicalVector copyBack() {
         RLogicalVector result = ((RAbstractLogicalVector) vector).materialize();
-        byte[] data = result.isTemporary() ? result.getDataWithoutCopying() : result.getDataCopy();
+        byte[] data = reuseData(result);
+        if (data == null) {
+            data = new byte[result.getLength()];
+        }
         int length = vector.getLength();
         for (int i = 0; i < length; i++) {
             data[i] = RRuntime.int2logical(UnsafeAdapter.UNSAFE.getInt(address + (i * Unsafe.ARRAY_INT_INDEX_SCALE)));
@@ -260,7 +275,7 @@ final class LogicalWrapper extends TemporaryWrapper {
 
 final class DoubleWrapper extends TemporaryWrapper {
 
-    public DoubleWrapper(RAbstractDoubleVector vector) {
+    DoubleWrapper(RAbstractDoubleVector vector) {
         super(vector);
     }
 
@@ -280,7 +295,10 @@ final class DoubleWrapper extends TemporaryWrapper {
     @TruffleBoundary
     protected RDoubleVector copyBack() {
         RDoubleVector result = ((RAbstractDoubleVector) vector).materialize();
-        double[] data = result.isTemporary() ? result.getDataWithoutCopying() : result.getDataCopy();
+        double[] data = reuseData(result);
+        if (data == null) {
+            data = new double[vector.getLength()];
+        }
         UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, vector.getLength() * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
         UnsafeAdapter.UNSAFE.freeMemory(address);
         return RDataFactory.createDoubleVector(data, false);
@@ -289,7 +307,7 @@ final class DoubleWrapper extends TemporaryWrapper {
 
 final class ComplexWrapper extends TemporaryWrapper {
 
-    public ComplexWrapper(RAbstractComplexVector vector) {
+    ComplexWrapper(RAbstractComplexVector vector) {
         super(vector);
     }
 
@@ -311,7 +329,10 @@ final class ComplexWrapper extends TemporaryWrapper {
     @TruffleBoundary
     protected RComplexVector copyBack() {
         RComplexVector result = ((RAbstractComplexVector) vector).materialize();
-        double[] data = result.isTemporary() ? result.getDataWithoutCopying() : result.getDataCopy();
+        double[] data = reuseData(result);
+        if (data == null) {
+            data = new double[result.getLength() * 2];
+        }
         UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_DOUBLE_BASE_OFFSET, vector.getLength() * 2 * Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
         UnsafeAdapter.UNSAFE.freeMemory(address);
         return RDataFactory.createComplexVector(data, false);
@@ -320,7 +341,7 @@ final class ComplexWrapper extends TemporaryWrapper {
 
 final class RawWrapper extends TemporaryWrapper {
 
-    public RawWrapper(RAbstractRawVector vector) {
+    RawWrapper(RAbstractRawVector vector) {
         super(vector);
     }
 
@@ -340,7 +361,10 @@ final class RawWrapper extends TemporaryWrapper {
     @TruffleBoundary
     protected RRawVector copyBack() {
         RRawVector result = ((RAbstractRawVector) vector).materialize();
-        byte[] data = result.isTemporary() ? result.getDataWithoutCopying() : result.getDataCopy();
+        byte[] data = reuseData(result);
+        if (data == null) {
+            data = new byte[result.getLength()];
+        }
         UnsafeAdapter.UNSAFE.copyMemory(null, address, data, Unsafe.ARRAY_BYTE_BASE_OFFSET, vector.getLength() * Unsafe.ARRAY_BYTE_INDEX_SCALE);
         UnsafeAdapter.UNSAFE.freeMemory(address);
         return RDataFactory.createRawVector(data);
@@ -352,7 +376,7 @@ final class RawWrapper extends TemporaryWrapper {
  */
 public interface CRFFI {
 
-    public static abstract class InvokeCNode extends RBaseNode {
+    abstract class InvokeCNode extends RBaseNode {
 
         /**
          * Invoke the native method identified by {@code symbolInfo} passing it the arguments in
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 62336feae6fcca50ce1ef0d698422896e9e5e667..2a79a1339b1279cdf234b83520f240aa8b4381ac 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,6 +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.nmath.RandomFunctions.RandomNumberProvider;
 
 public final class RMultinom {
@@ -31,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, double[] prob, int maxK, int[] rN, int rnStartIdx, RandomNumberProvider rand, Rbinom rbinom) {
+    public static boolean rmultinom(int nIn, DoubleAccessor 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
@@ -52,7 +53,7 @@ public final class RMultinom {
          */
         /* LDOUBLE */double pTot = 0.;
         for (int k = 0; k < maxK; k++) {
-            double pp = prob[k];
+            double pp = prob.getDataAt(k);
             if (!Double.isFinite(pp) || pp < 0. || pp > 1.) {
                 rN[rnStartIdx + k] = RRuntime.INT_NA;
                 return false;
@@ -75,7 +76,7 @@ public final class RMultinom {
         /* Generate the first K-1 obs. via binomials */
         for (int k = 0; k < maxK - 1; k++) {
             /* (p_tot, n) are for "remaining binomial" */
-            /* LDOUBLE */double probK = prob[k];
+            /* LDOUBLE */double probK = prob.getDataAt(k);
             if (probK != 0.) {
                 double pp = probK / pTot;
                 // System.out.printf("[%d] %.17f\n", k + 1, pp);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/AccessVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/AccessVector.java
deleted file mode 100644
index 13fc7233e5c65c11440bb48b60d27cb906d18509..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/AccessVector.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.runtime.ops;
-
-import static com.oracle.truffle.r.runtime.RRuntime.isNA;
-
-import com.oracle.truffle.api.CompilerDirectives;
-import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.profiles.BranchProfile;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.context.RContext;
-import com.oracle.truffle.r.runtime.data.RComplex;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
-import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-
-public abstract class AccessVector {
-
-    public static final class Int<T extends RAbstractIntVector, S> extends Node {
-
-        @SuppressWarnings("unchecked")
-        public S init(T vector) {
-            return (S) vector;
-        }
-
-        @SuppressWarnings("unchecked")
-        public int getInt(S store, int index) {
-            return ((T) store).getDataAt(index);
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
index 954b4408215496c42ecfb13cedfdc609bcdd657f..42e5cfb447cd6341ed564e3e7a6ca09c4b874fde 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
@@ -35,9 +35,7 @@ import com.oracle.truffle.r.runtime.rng.user.UserRNG;
  * The fact that the R programmer can set {@code .Random.seed} explicitly, as opposed to the
  * recommended approach of calling {@code set.seed}, is something of a pain as it changes the
  * {@link Kind}, the {@link NormKind} and the actual seeds all in one go and in a totally
- * uncontrolled way, which then has to be checked. Currently we do not support reading it, although
- * we do create/update it when the seed/kind is changed, primarily as a debugging aid. N.B. GnuR
- * updates it on <i>every</i> random number generation!
+ * uncontrolled way, which then has to be checked.
  *
  * Important note: make sure to invoke {@link #getRNGState()} before invoking any other methods from
  * this class and to invoke {@link #putRNGState()} when done witch random number generation.
@@ -387,9 +385,13 @@ public class RRNG {
                 seeds = new int[]{(int) seedsObj};
             } else if (seedsObj instanceof RIntVector) {
                 RIntVector seedsVec = (RIntVector) seedsObj;
-                seeds = seedsVec.getDataWithoutCopying();
+                seeds = seedsVec.getReadonlyData();
                 if (seeds == currentGenerator().getSeeds()) {
-                    // no change of the .Random.seed variable
+                    // Optimization: if the array instance has not changed, then the .Random.seed
+                    // variable was not changed, nor materialized to a native mirror, we still hold
+                    // the same reference to its underlying data. Note: setISeed is potentially
+                    // doing some clean-up of the data, so it may not be O(1) operation and it's
+                    // good to avoid it.
                     return;
                 }
             } else if (seedsObj instanceof int[]) {
diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/man/testrffi-package.Rd b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/man/testrffi-package.Rd
index 2ea30d34d29ec665df649be69ddc218e38fb8d9f..c5ca498a5561545c0c5c5df8a5d02982dc945eb3 100644
--- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/man/testrffi-package.Rd
+++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/man/testrffi-package.Rd
@@ -1,8 +1,8 @@
+\title{Tests the R FFI interface}
 \name{testrffi-package}
 \alias{testrffi-package}
 \alias{testrffi}
 \docType{package}
-\title{Tests the R FFI interface}
 \description{Tests the R FFI interface via a collection of R functions that
 call down to native code using .Call which then typically make R FFI upcalls to
 test the individual functions. The set of tests is not comprehensive.
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java
index d63388c943f734cb04d2a5c63bab81209d790252..04ecbe3bd7112ff3e75835fd90ad3820cbb48a41 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java
@@ -49,7 +49,7 @@ public class RPairListTests {
     public void testToList() {
         RPairList pairList = RDataFactory.createPairList(1, RDataFactory.createPairList(2, RNull.instance, "name2"), "name1");
         RList result = pairList.toRList();
-        assertArrayEquals(new String[]{"name1", "name2"}, result.getNames().getDataWithoutCopying());
+        assertArrayEquals(new String[]{"name1", "name2"}, result.getNames().getReadonlyData());
         assertArrayEquals(new Object[]{1, 2}, result.getDataWithoutCopying());
     }
 }